package com.bestcem.xm.user.service.impl;

import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.bp.xm.user.grpc.v1.services.UserConditionLevel;
import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.exception.ServiceException;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.EmailUtil;
import com.bestcem.xm.common.core.uitls.TransactionHelper;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.component.security.dto.TokenDTO;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.user.config.properties.SettingProperties;
import com.bestcem.xm.user.constant.BusinessConstant;
import com.bestcem.xm.user.constant.CommonConstant;
import com.bestcem.xm.user.constant.SmsConstant;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.controller.vo.user.request.UserInfoRequestVO;
import com.bestcem.xm.user.dao.UserAccountDao;
import com.bestcem.xm.user.dao.UserGroupDao;
import com.bestcem.xm.user.dao.UserGroupLevelDao;
import com.bestcem.xm.user.dao.UserRoleDao;
import com.bestcem.xm.user.entity.base.PageParam;
import com.bestcem.xm.user.entity.mysql.User;
import com.bestcem.xm.user.entity.pojo.*;
import com.bestcem.xm.user.enums.*;
import com.bestcem.xm.user.grpc.client.IndustryGrpcService;
import com.bestcem.xm.user.grpc.client.PackageGrpcService;
import com.bestcem.xm.user.grpc.client.dto.IndustryDTO;
import com.bestcem.xm.user.grpc.client.dto.PackageDTO;
import com.bestcem.xm.user.grpc.service.converter.UserConditionConvert;
import com.bestcem.xm.user.mq.message.user.SmsMessage;
import com.bestcem.xm.user.mq.send.biz.UserMessageSendService;
import com.bestcem.xm.user.service.*;
import com.bestcem.xm.user.service.dto.PageRequestDTO;
import com.bestcem.xm.user.service.dto.PageResponseDTO;
import com.bestcem.xm.user.service.dto.PageUserResponseDTO;
import com.bestcem.xm.user.service.dto.group.SaveUserToGroupDTO;
import com.bestcem.xm.user.service.dto.group.UserGroupDTO;
import com.bestcem.xm.user.service.dto.group.UserWithGroupDTO;
import com.bestcem.xm.user.service.dto.role.RolePermissionDTO;
import com.bestcem.xm.user.service.dto.role.UserRoleDTO;
import com.bestcem.xm.user.service.dto.user.*;
import com.bestcem.xm.user.service.third.ApiHelperService;
import com.bestcem.xm.user.util.UserAsyncUtil;
import com.bestcem.xm.user.util.business.*;
import com.bestcem.xm.user.util.convert.UserConvert;
import com.bestcem.xm.user.util.converter.UserConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.joining;

/**
 * @author Linked <zhijian.lin@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/1 14:51
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserConvert userConvert;

    @Resource
    private RedisService redisService;

    @Resource
    private UserCacheUtil userCacheUtil;

    @Resource
    private UserAccountDao userAccountDao;

    @Resource
    private UserUserGroupService userUserGroupService;

    @Resource
    private UserGroupService userGroupService;

    @Resource
    private ApiHelperService apiHelperService;

    @Resource
    private MailService mailService;

    @Resource
    private UserSmsService userSmsService;

    @Resource
    private UserUtil userUtil;

    @Resource
    private UserUserRoleService userUserRoleService;

    @Resource
    private OrganizationService organizationService;

    //@Resource
    //private UserMessageSender userMessageSender;

    @Resource
    private UserMessageSendService userMessageSendService;

    //@Resource
    //private WeChatMessageSender weChatMessageSender;

    @Resource
    private UserBusinessService userBusinessService;

    @Resource
    private RolePermissionService rolePermissionService;

    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    @Resource
    private SettingProperties settingProperties;

    @Resource
    private UserJwtTokenUtil userJwtTokenUtil;

    @Resource
    private PackageGrpcService packageGrpcService;

    @Resource
    private UserMfaSettingService userMfaSettingService;

    @Resource
    private IndustryGrpcService industryGrpcService;

    //@Resource
    //private OrganizationCustomSettingService organizationCustomSettingService;
    @Resource
    private UserGroupLevelDao userGroupLevelDao;
    @Resource
    private UserGroupDao userGroupDao;
    @Resource
    private UserRoleDao userRoleDao;

    @Lazy
    @Resource
    private UserAsyncUtil userAsyncUtil;

    /**
     * 重置密码设置的token有效时长
     */
    public static final long RESET_PASSWORD_TOKEN_TIMEOUT = 2 * 60 * 60L;

    @Override
    public ServiceResult<String> saveUserAccount(SaveUserAccountDTO accountDTO, String remoteHost, String protocol) {
        String orgId = accountDTO.getOrgId();

        // 不允许给账号分配系统管理员角色（现在没有超管）
        ServiceResult<String> adminRoleResult = roleService.getAdminRole(orgId);
        String roleAdminId = adminRoleResult.getData();
        if (CollectionUtils.isNotEmpty(accountDTO.getRoleList()) && accountDTO.getRoleList().contains(roleAdminId)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.PERMISSION_DENY, "admin role is forbidden");
        }

        // 当前公司下的角色
//        ServiceResult<List<UserRoleDTO>> roleListRst = userService.getRoleAccount(orgId);
//        if (CollectionUtils.isNotEmpty(roleListRst.getData())) {
//            List<String> roleIdList = roleListRst.getData().stream().map(UserRoleDTO::getRoleId).collect(Collectors.toList());
//            if (!roleIdList.containsAll(accountDTO.getRoleList())) {
//                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "非法roleId");
//            }
//        }

        // 根据当前org的mfa_setting判断用户手机号是否可以为空
        boolean phoneIsNeed = checkPhoneIsNeed(orgId);
        if (phoneIsNeed && StringUtils.isBlank(accountDTO.getPhone())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "mobile is required");
        }

        List<UserDTO> userListByUserName = userService.getUserListByUsernameOrEmailOrPhone(accountDTO.getOrgId(), accountDTO.getUserName(), null, null);
        if (CollectionUtils.isNotEmpty(userListByUserName)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.STATUS_CHANGED, "username is found");
        }

        // 账户手机邮箱是否重复判断
        ServiceResult<Boolean> exist = checkUserByEmailOrPhone(orgId, accountDTO.getPhone(), accountDTO.getEmail(), null);
        if (!exist.isSuccess()) {
            return ServiceResult.fail(exist.getErrorData(), exist.getMsg());
        }

        // 检验租户配额
        /*ServiceResult<Boolean> result = checkUserQuota(orgId, 1);
        // 用户数已达上限
        if (!Boolean.TRUE.equals(result.getData())) {
            return ServiceResult.fail(result.getErrorData(), result.getMsg());
        }*/

        // 保存账号
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(accountDTO, userDTO);
        userDTO.setStatus(UserStatusEnum.INACTIVATED.getStatus());
        userDTO.setBiShareFlag(RoleBiShareEnum.NO_SHARE.getType());
        String userId = userService.saveUser(orgId, userDTO, accountDTO.getGroupIdList(), accountDTO.getRoleList());
        // MQ消息
        userMessageSendService.publishUserCreate(userDTO.getUserId(), accountDTO.getGroupIdList());

        // 更新租户消费额
        updateUserConsumption(orgId, 1);

        // 清除mfa缓存
        userCacheUtil.delete(userCacheUtil.buildKey(UserCacheKeyConstant.USER_MFA_CHECK_BIND, userDTO.getPhone(), orgId));

        // 异步发送激活邮箱
        userAsyncUtil.activeEmailManyAsync(Collections.singletonList(userId), remoteHost, protocol);

        return ServiceResult.success(userId);

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ServiceResult<String> updateUserAccount(UpdateUserAccountDTO accountDTO) {
        UserDO userDO = userAccountDao.selectByPrimaryKey(accountDTO.getUserId());
        if (Objects.isNull(userDO)) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, String.format("old_user user_id=[%s] not found.", accountDTO.getUserId()));
        }

        // 获取系统管理员
        ServiceResult<UserDTO> adminUserResult = userBusinessService.getAdminUserByOrgId(accountDTO.getOrgId());
        UserDTO adminUser = adminUserResult.getData();
        // 不允许修改管理员
        if (Objects.nonNull(adminUser) && accountDTO.getUserId().equals(adminUser.getUserId())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.PERMISSION_DENY, "admin is forbidden");
        }


        // 不允许给账号分配系统管理员角色（现在没有超管）
        ServiceResult<String> adminRoleResult = roleService.getAdminRole(accountDTO.getOrgId());
        String roleAdminId = adminRoleResult.getData();
        List<String> newRoleIdList = accountDTO.getRoleList();
        if (CollectionUtils.isNotEmpty(newRoleIdList) && newRoleIdList.contains(roleAdminId)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.PERMISSION_DENY, "admin role is forbidden");
        }

        // 根据当前org的mfa_setting判断用户手机号是否可以为空
        boolean phoneIsNeed = checkPhoneIsNeed(accountDTO.getOrgId());
        if (phoneIsNeed && StringUtils.isBlank(accountDTO.getPhone())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "mobile is required");
        }

        List<UserDTO> userListByUserName = userService.getUserListByUsernameOrEmailOrPhone(accountDTO.getOrgId(), accountDTO.getUserName(), null, null);
        if (CollectionUtils.isNotEmpty(userListByUserName) && !userListByUserName.get(0).getUserId().equals(accountDTO.getUserId())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.DUPLICATE, "username is found");
        }

        // 账户手机邮箱是否重复判断
        ServiceResult<Boolean> exist = checkUserByEmailOrPhone(accountDTO.getOrgId(), accountDTO.getPhone(), accountDTO.getEmail(), accountDTO.getUserId());
        if (!exist.isSuccess()) {
            return ServiceResult.fail(exist.getErrorData(), exist.getMsg());
        }
        // 更新用户组织
        userUserGroupService.updateUserGroups(accountDTO.getOrgId(), accountDTO.getUserId(), accountDTO.getGroupIdList());

        // 查询用户当前的角色id
        UserUserRoleDTO userUserRoleDTO = new UserUserRoleDTO();
        userUserRoleDTO.setUserId(accountDTO.getUserId());
        ServiceResult<List<UserUserRoleDTO>> roleIdsService = userUserRoleService.listByCondition(userUserRoleDTO);
        List<String> oldRoleIdList = roleIdsService.getData().stream().map(UserUserRoleDTO::getRoleId).collect(Collectors.toList());

        // 投放审核员
        ServiceResult<String> deliverRoleResult = roleService.getDeliverCheckRole(accountDTO.getOrgId());
        String deliverRoleId = deliverRoleResult.getData();

        // 如果是给当前系统管理员添加角色，需要把他从oldRoleIdList移除，避免被后续的操作删除
        if (CollectionUtils.isNotEmpty(oldRoleIdList)) {
            oldRoleIdList.remove(roleAdminId);
            // 传给后端的角色是不包含投放审核员的角色id的，需要把他从oldRoleIdList移除，避免被后续的操作删除
            oldRoleIdList.remove(deliverRoleId);
        }

        // 高级管理员
        ServiceResult<String> seniorRoleResult = roleService.getSeniorAdminRole(accountDTO.getOrgId());
        String seniorRoleId = seniorRoleResult.getData();
        // 如果当前用户非系统管理员，传给后端的角色是不包含高级管理员的角色id的，需要把他从oldRoleIdList移除，避免被后续的操作删除
        if (CollectionUtils.isNotEmpty(oldRoleIdList) && oldRoleIdList.contains(seniorRoleId) && !accountDTO.getCurrentId().equals(adminUser.getUserId())) {
            oldRoleIdList.remove(seniorRoleId);
        }

        // 检查用户的角色是否变化，如果变化则更新用户角色表
        ServiceResult<Boolean> roleChangeAndUpdate = userUserRoleService.checkUserRoleChangeAndUpdate(accountDTO.getOrgId(), userDO.getUserId(), newRoleIdList, oldRoleIdList, accountDTO.getCurrentId());
        // 用户角色是否变化 清空个人首页
        if (Boolean.TRUE.equals(roleChangeAndUpdate.getData())) {
            userDO.setUserIndex(null);
        }
        // 修改手机号码，取消关联微信unionid
        if (StringUtils.isNotBlank(accountDTO.getPhone()) && !accountDTO.getPhone().equals(userDO.getPhone())) {
            userDO.setWxUnionid(null);
        }
        // 是否是内部用户
        boolean checkUserIsInner = userUtil.checkUserIsInner(accountDTO.getPhone(), accountDTO.getEmail(), "");
        userDO.setInnerFlag(BooleanStatusEnum.toInteger(checkUserIsInner));

        userDO.setUserId(accountDTO.getUserId());
        userDO.setUserName(accountDTO.getUserName());
        userDO.setName(accountDTO.getName());
        userDO.setContent(accountDTO.getContent());
        userDO.setEmail(accountDTO.getEmail());
        userDO.setPhone(accountDTO.getPhone());
        userDO.setOperatorId(accountDTO.getCurrentId());
        userAccountDao.updateByPrimaryKey(userDO);
        // 消息通知
        userMessageSendService.publishUserUpdate(userDO.getUserId(), accountDTO.getGroupIdList());
        //userMessageSender.publishUserUpdateContacts(userDO.getUserId(), null, userDO.getUserName(), userDO.getPhone(), userDO.getEmail());
        // 检查用户的角色中是否对超级管理员的角色增减操作,如果是则添加高级管理员项目入口
        userUserRoleService.checkSeniorRole(accountDTO.getOrgId(), userDO.getUserId(), newRoleIdList, oldRoleIdList);
        return ServiceResult.success(accountDTO.getUserId());

    }

    /**
     * 根据当前org的mfa_setting判断用户手机号是否可以为空
     * true 需要 false不需要
     *
     * @param orgId
     * @return java.lang.Boolean
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/18 16:27
     */
    private boolean checkPhoneIsNeed(String orgId) {
        ServiceResult<UserMfaSettingDTO> mfaResult = userMfaSettingService.getMfaSettingByOrgId(orgId);
        if (mfaResult.isSuccess() && Objects.nonNull(mfaResult.getData())) {
            UserMfaSettingDTO userMfaSettingDTO = mfaResult.getData();
            if (userMfaSettingDTO.getOpenMfa().equals(UserEnum.USER_YES.getFlag()) &&
                    userMfaSettingDTO.getAuthMethod().equals(MfaSettingAuthMethodEnum.MFASETTING_AUTH_METHOD_SMS.getType())) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 禁用/启用账号
     *
     * @param currentToken 当前token
     * @param userId       用户id
     * @param status       状态
     * @return com.bestcem.xm.util.ServiceResult<com.bestcem.xm.user.service.dto.user.UserDetailDTO>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/2 10:48
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<UserDTO> updateUserStatus(TokenDTO currentToken, String userId, int status) {
        UserDO oldUser = userAccountDao.selectByPrimaryKey(userId);
        if (Objects.isNull(oldUser)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "userId不正确");
        }
        String orgId = currentToken.getOrgId();

        if (oldUser.getStatus().equals(UserStatusEnum.INACTIVATED.getStatus())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "用户未激活!");
        }

        if (oldUser.getStatus() == status) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "status不能与用户当前状态相同!");
        }

        // 发送MQ
        userMessageSendService.publishUserUpdate(userId, new ArrayList<>());

        User user = new User();
        user.setUserId(userId);
        user.setOperatorId(currentToken.getUserId());
        boolean checkUserIsInner = userUtil.checkUserIsInner(oldUser.getPhone(), oldUser.getEmail(), "");
        user.setInnerFlag(BooleanStatusEnum.toInteger(checkUserIsInner));

        //禁用
        if (status == UserStatusEnum.DISABLED.getStatus()) {
            // 更新用户状态为已失效
            user.setStatus(UserStatusEnum.DISABLED.getStatus());
            int i = userAccountDao.updateByPrimaryKeySelective(user);
            if (i != 1) {
                log.error("update user error userId:" + userId);
                return ServiceResult.fail("禁用用户失败 userId:" + userId);
            }

            // 将redis缓存中的对应租户用户数消费额减1,并发送mq消息
            userService.updateUserConsumption(orgId, -1);

            // 根据user_id在redis中失效token
            userJwtTokenUtil.updateTokenVersion(userId);

            return ServiceResult.success(userConvert.do2Dto(userAccountDao.selectByPrimaryKey(userId)));
        }

        //启用
        if (status == UserStatusEnum.ACTIVATED.getStatus()) {
            // 检查租户用户限额 并在redis中获取当前使用的套餐
            ServiceResult<Boolean> userQuota = userService.checkUserQuota(orgId, 1);
            if (!userQuota.isSuccess()) {
                return ServiceResult.fail(ResourceErrorCodeEnum.QUOTA_REACHED);
            }

            // 如果用户数没有达到上限：更新用户信息
            user.setStatus(UserStatusEnum.ACTIVATED.getStatus());
            int i = userAccountDao.updateByPrimaryKeySelective(user);
            if (i != 1) {
                log.error("update user error userId:" + userId);
                return ServiceResult.fail("启用用户失败 userId:" + userId);
            }

            // 新增租户用户数消费额,并发送mq消息
            userService.updateUserConsumption(orgId, 1);

            return ServiceResult.success(userConvert.do2Dto(userAccountDao.selectByPrimaryKey(userId)));
        }

        return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE.getMsg());
    }

    @Override
    public ServiceResult<Boolean> clickIntroduction(String userId) {
        // 更新用户的 showGuide 为 false
        User user = new User();
        user.setUserId(userId);
        // 用户确认点击版本公告，则表示下次不用显示引导页，也就是引导页显示标志改为false
        user.setShowGuide(BooleanStatusEnum.NO.getStatus());
        userAccountDao.updateByPrimaryKeySelective(user);

        return ServiceResult.success(Boolean.TRUE);
    }

    @Override
    public ServiceResult<Integer> addGuideRecord(String guide, String userId) {
        if (StringUtils.isBlank(guide)) {
            return ServiceResult.success();
        }
        UserDO user = userAccountDao.selectByPrimaryKey(userId);
        if (Objects.isNull(user)) {
            return ServiceResult.success(0);
        }
        Set<String> records = new HashSet<>();
        if (StringUtils.isNotBlank(user.getShowGuideRecords())) {
            records.addAll(JSON.parseArray(user.getShowGuideRecords(), String.class));
        }
        // 往用户的 showGuideRecords 字段中追加一个 guide
        records.add(guide);
        User param = new User();
        param.setUserId(userId);
        param.setShowGuideRecords(JSON.toJSONString(records));
        userAccountDao.updateByPrimaryKeySelective(param);

        return ServiceResult.success(1);
    }

    @Override
    public ServiceResult<String> encodeValue(String value) throws UnsupportedEncodingException {
        return ServiceResult.success(URLEncoder.encode(value, StandardCharsets.UTF_8.toString()));
    }

    /**
     * url 地址特殊字符转码
     *
     * @param orgUrl
     * @param uid
     * @param token
     * @param email
     * @return
     * @author handsome
     * @date 2022/7/21 11:30
     */
    private String encodedURL(String orgUrl, String uid, String token, String email) {

        Map<String, String> requestParams = new LinkedHashMap<>();
        requestParams.put("uid", uid);
        requestParams.put("token", token);
        requestParams.put("email", email);

        return requestParams.keySet().stream()
                .map(key -> {
                    try {
                        return key + "=" + encodeValue(requestParams.get(key)).getData();
                    } catch (UnsupportedEncodingException e) {
                        throw new RuntimeException(e);
                    }
                })
                .collect(joining("&", orgUrl + "?", ""));
    }

    @Override
    public ServiceResult<FindPasswordResultDTO> findPassword(FindPasswordParamDTO paramDTO) {
        // python引用：apps_mysql/user/v3/handlers.py:322
        // 参数校验
        FindPasswordTypeEnum findType = FindPasswordTypeEnum.getByType(paramDTO.getType());
        ServiceResult<String> checkResult = checkFindPasswordParam(findType, paramDTO.getEmail(), paramDTO.getMobile(),
                paramDTO.getVcode());
        if (!checkResult.isSuccess()) {
            return ServiceResult.fail(checkResult.getErrorData(), checkResult.getMsg());
        }
        String contact = checkResult.getData();

        /**
         * 开始找回密码，官网找回密码入口
         */
        List<String> orgCodes = new ArrayList<>();
        List<UserDO> users = new ArrayList<>();
        String customDomainUrl = "";
        UserDO user;

        // 根据是否org_code 判断是在官网还是在租户系统页
        if (StringUtils.isBlank(paramDTO.getOrgCode())) {
            // 根据手机号或者邮箱查询用户列表
            users = userAccountDao.getUserByPhoneOrEmail(contact, contact);
            users = users.stream().filter(u -> u.getStatus().equals(UserStatusEnum.ACTIVATED.getStatus())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(users)) {
                return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未找到对应的用户信息");
            }
            // 获取第一个用户信息
            user = users.get(0);
            // 根据用户列表查询对应的orgCode列表
            List<String> orgIds = users.stream().map(UserDO::getOrgId).collect(Collectors.toList());
            ServiceResult<List<String>> orgCodesResult = organizationService.selectOrgCodesByIds(orgIds);
            if (!orgCodesResult.isSuccess()) {
                return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应的公司信息");
            }
            orgCodes.addAll(orgCodesResult.getData());
        } else {
            // 根据org_code查询公司信息得到org_id
            ServiceResult<OrganizationDTO> organizationServiceResult = organizationService.selectByOrgCode(paramDTO.getOrgCode());
            if (!organizationServiceResult.isSuccess() || Objects.isNull(organizationServiceResult.getData())) {
                return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到orgCode对应的公司信息");
            }
            // 根据orgId和手机号或者和邮箱查询用户信息
            String orgId = organizationServiceResult.getData().getOrgId();
            user = userAccountDao.getUserByOrgIdAndPhoneOrEmail(orgId, contact, contact);
            if (Objects.isNull(user) || !user.getStatus().equals(UserStatusEnum.ACTIVATED.getStatus())) {
                return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未找到对应的用户信息");
            }
            users.add(user);
            orgCodes.add(paramDTO.getOrgCode());
            if (!paramDTO.getRemoteHost().contains(settingProperties.getXmServerHost())) {
                customDomainUrl = userUtil.getCorpUrl(orgId, paramDTO.getOrgCode(), "", "");
            }
        }

        // 过滤是否有有效状态的用户
        long count = users.stream().filter(u -> u.getStatus().equals(UserStatusEnum.ACTIVATED.getStatus())).count();
        if (count == 0) {
            return ServiceResult.fail(ResourceErrorCodeEnum.STATUS_CHANGED, "未查询到有效状态的用户信息");
        }

        // 将用户id使用;分隔成字符串(python默认;)
        String userIdStrs = users.stream().map(UserDO::getUserId).collect(Collectors.joining("_"));
        String activateTokenKey = userCacheUtil.buildKey(UserCacheKeyConstant.RESET_TOKEN_KEY, userIdStrs);
        // 查询重置密码redis缓存的activate_token
        String activateToken = userCacheUtil.get(activateTokenKey);
        if (StringUtils.isNotBlank(activateToken)) {
            // 重刷token的时间
            userCacheUtil.expire(activateTokenKey, RESET_PASSWORD_TOKEN_TIMEOUT);
        } else {
            // 自动生成active_token
            activateToken = UUID.randomUUID().toString().replace("-", "");
            userCacheUtil.setEx(activateTokenKey, activateToken, RESET_PASSWORD_TOKEN_TIMEOUT, TimeUnit.SECONDS);
        }

        // 开始发送短信或者邮件
        try {
            String orgEmailTemplate = StringFormatUtil.readHtmlTemplateContent(EmailTemplateEnum.ORGANIZATION_EMAIL_TEMPLATE.getFileName());
            String orgUrl = "";
            StringBuilder orgUrlTemplateStr = new StringBuilder();
            Map<String, Object> param = new HashMap<>();
            if (StringUtils.isNotBlank(customDomainUrl)) {
                orgUrl = customDomainUrl;
                param.put("org_url", customDomainUrl);
                orgUrlTemplateStr.append(StringFormatUtil.format(orgEmailTemplate, param));
            } else {
                for (String code : orgCodes) {
                    orgUrl = userUtil.getCorpUrl(code);
                    param.put("org_url", orgUrl);
                    orgUrlTemplateStr.append(StringFormatUtil.format(orgEmailTemplate, param));
                }
            }

            if (findType.equals(FindPasswordTypeEnum.EMAIL)) {
                // 组装重置密码链接
                // url 转义 否则 浏览器请求处理错误
                String shortUrl = encodedURL(orgUrl + "/resetPassword", URLEncoder.encode(userIdStrs, StandardCharsets.UTF_8.toString()), activateToken, contact);

                // 临时注释 生成短连接
                ServiceResult<String> shortActivateUrl = apiHelperService.aioConvertShortUrl(shortUrl, customDomainUrl);
                if (!shortActivateUrl.isSuccess()) {
                    log.error("生成重置密码短链接失败！");
                } else {
                    shortUrl = shortActivateUrl.getData();
                }

                // 邮箱校验，需要发送邮件告知重置密码的链接
                String fileName = EmailTemplateEnum.RESET_PASSWORD_TEMPLATE.getFileName();
                HashMap<String, Object> map = new HashMap<>();
                map.put("name", user.getName());
                map.put("hours", 2);
                map.put("activate_url", shortUrl);
                map.put("today", DateUtil.convertDteToString(new Date(), "yyyy年MM月dd日"));
                map.put("org_url_trs", orgUrlTemplateStr.toString());
                map.put("email_oss_path", getEmailOssPath());
                String subject = settingProperties.getBestcemEmailSign() + "重置密码";
                mailService.emailSendAndNotifyOm(new String[]{contact}, null, subject, fileName, map);
                return ServiceResult.success();
            }
            return ServiceResult.success(new FindPasswordResultDTO(this.encodeValue(userIdStrs).getData(), activateToken));
        } catch (Exception e) {
            log.error("找回密码异常：{}", e);
            redisService.del(activateTokenKey);
        }

        return ServiceResult.success();
    }

    /*@Resource
    private OssService ossService;*/


    @Autowired
    private StorageService storageService;

    private String getEmailOssPath() {
        //return ossService.getUrlPrefix() + "email/";
        return storageService.getPropertiesValueBy(null, "domain") + storageService.getPropertiesValueBy(null, "base-path") + "email/";
    }

    @Override
    public ServiceResult<UserDTO> selectById(String userId) {
        if (StringUtils.isBlank(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "用戶id不能为空");
        }
        UserDO user = userAccountDao.selectByPrimaryKey(userId);
        return ServiceResult.success(userConvert.do2Dto(user));
    }

    @Override
    public ServiceResult<List<UserDTO>> listByCondition(UserDTO userDTO) {
        // 校验参数
        if (userDTO == null) {
            return ServiceResult.fail("参数不能为空");
        }
        // 查询
        return ServiceResult.success(userConvert.dos2Dtos(userAccountDao.listByCondition(userConvert.dto2Do(userDTO))));
    }

    @Override
    public ServiceResult<Integer> updateById(UserDTO userDTO) {
        // 校验参数
        if (Objects.isNull(userDTO)) {
            return ServiceResult.fail("参数不能为空");
        }
        if (!ObjectId.isValid(userDTO.getUserId())) {
            return ServiceResult.fail("参数格式不正确");
        }
        // 更新
        UserDO userDO = userConvert.dto2Do(userDTO);
        return ServiceResult.success(userAccountDao.updateByPrimaryKeySelective(userConvert.do2Mysql(userDO)));
    }

    /**
     * 账户手机邮箱是否重复判断
     *
     * @param orgId  : 公司id
     * @param phone  : 手机
     * @param email  : 邮箱
     * @param userId : 待检查的用户id
     * @return
     * @author Linked <zhijian.lin@idiaoyan.com>
     * @date 2022/3/1 17:11
     */
    @Override
    public Boolean checkUserByEmailAndPhone(String orgId, String phone, String email, String userId) {
        return userAccountDao.checkUserByEmailAndPhone(orgId, phone, email, userId) > 0;
    }

    /**
     * 账户手机邮箱是否重复判断
     *
     * @param orgId  : 公司id
     * @param phone  : 手机
     * @param email  : 邮箱
     * @param userId : 待检查的用户id
     * @return
     * @author Linked <zhijian.lin@idiaoyan.com>
     * @date 2022/3/1 17:11
     */
    @Override
    public ServiceResult<Boolean> checkUserByEmailOrPhone(String orgId, String phone, String email, String userId) {
        if (StringUtils.isNotBlank(phone) && userAccountDao.checkUserByEmailAndPhone(orgId, phone, null, userId) > 0) {
            return ServiceResult.fail(ValidationErrorCodeEnum.PHONE_EXISTS_ERROR, "mobile is Found");
        }
        if (StringUtils.isNotBlank(email) && userAccountDao.checkUserByEmailAndPhone(orgId, null, email, userId) > 0) {
            return ServiceResult.fail(ValidationErrorCodeEnum.EMAIL_EXISTS_ERROR, "email is Found");
        }
        return ServiceResult.success(Boolean.TRUE);
    }

    @Override
    public Boolean checkUserBySilentId(String orgId, String silentId) {
        return userAccountDao.checkUserBySilentId(orgId, silentId) > 0;
    }

    /**
     * 检查租户用户限额
     * 注意返回值不会返回false，请不要拿false直接比较
     * apps_mysql/user/util/utils.py:1524
     * 经python确认notify永远为false,故去除通知逻辑
     *
     * @param orgId  公司id
     * @param amount 数量
     * @return void
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/03/14 17:24
     */
    @Override
    public ServiceResult<Boolean> checkUserQuota(String orgId, Integer amount) {
        String orgConsumptionKey = UserCacheKeyConstant.USER_PACK_CONSUMPTION + orgId;
        ServiceResult<OrganizationDTO> organization = organizationService.selectByPrimaryKey(orgId);
        // python从缓存USER:pack_perm_{org_id}中取userQuota,但套餐已经迁移至om,故请求om套餐接口
        PackageDTO packageDTO = packageGrpcService.getById(organization.getData().getPackageId());
        Integer userQuota = packageDTO.getUserQuota();
        Object useTotal = redisService.hashGet(orgConsumptionKey, QuotaConsumptionEnum.USER.getKey());
        Integer usage = Objects.isNull(useTotal) ? 0 : Integer.parseInt(useTotal.toString());
        // -1表示不限额
        if (userQuota != -1 && usage + amount > userQuota) {
            return ServiceResult.fail(ResourceErrorCodeEnum.QUOTA_REACHED, "用户数已达上限");
        }
        return ServiceResult.success(Boolean.TRUE);
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String saveUser(String orgId, UserDTO userDTO, List<String> groupIdList, List<String> roleIdList) {
        ServiceResult<OrganizationDTO> serviceResult = organizationService.selectByPrimaryKey(orgId);
        OrganizationDTO organization = serviceResult.getData();
        String rootGroupId = organization.getRootGroupId();

        userDTO.setOrgId(orgId);
        // 后台添加用户，acceptFlag = False
        userDTO.setAcceptFlag(UserAccpectFlagEnum.NOT_ACCPECT.getType());
        // 是否是内部用户
        boolean innerUser = userUtil.checkUserIsInner(userDTO.getPhone(), userDTO.getEmail(), "");
        userDTO.setInnerFlag(BooleanStatusEnum.toInteger(innerUser));
        // 新增用户
        this.insert(userDTO);

        // 插入用户角色表
        if (CollectionUtils.isNotEmpty(roleIdList)) {
            userUserRoleService.insertUserRoleList(organization.getOrgId(), userDTO.getUserId(), roleIdList, userDTO.getCreatorId());
        }

        // 将账号添加进组织
        if (CollectionUtils.isNotEmpty(groupIdList)) {
            for (String groupId : groupIdList) {
                SaveUserToGroupDTO userToGroupDTO = new SaveUserToGroupDTO();
                userToGroupDTO.setUserId(userDTO.getUserId());
                userToGroupDTO.setGroupId(groupId);
                userToGroupDTO.setRootGroupId(rootGroupId);
                userToGroupDTO.setCreatorId(userDTO.getUserId());
                userToGroupDTO.setOperatorId(userDTO.getUserId());
                userUserGroupService.saveUserToGroup(userToGroupDTO);
            }
        }
        return userDTO.getUserId();
    }

    @Override
    public void updateUserConsumption(String orgId, Integer amount) {
        // 用户限额缓存直接更新
        String consumption = UserCacheKeyConstant.USER_PACK_CONSUMPTION + orgId;
        redisService.hashIncr(consumption, QuotaConsumptionEnum.USER.getKey(), Long.valueOf(amount));
        // 统计用户数量 await redis_mq.publish(topics.user_org_quota_consumption,{'org_id': str(org_id), 'amount': amount, 'ttype': 'user_total'})
        //userMessageSender.publishQuotaConsumption(orgId, amount, QuotaConsumptionEnum.USER.getType());
    }

    @Override
    public ServiceResult<List<UserDTO>> selectList(UserDTO userDTO) {
        List<UserDO> userDOs = userAccountDao.selectList(userConvert.dto2Do(userDTO));
        return ServiceResult.success(userConvert.dos2Dtos(userDOs));
    }

    @Override
    public ServiceResult<Boolean> checkReviewer(String orgId, String userId) {
        if (StringUtils.isBlank(orgId) || StringUtils.isBlank(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId和userId都不能为空");
        }

        // 获取投放审核角色id
        String deliverCheckRoleId = roleService.getDeliverCheckRole(orgId).getData();
        if (deliverCheckRoleId == null) {
            return ServiceResult.success(Boolean.FALSE);
        }

        // 获取用户的角色id列表信息
        ServiceResult<Boolean> hasRoleRt = userBusinessService.hasRole(userId, orgId, deliverCheckRoleId);
        if (!hasRoleRt.isSuccess()) {
            return ServiceResult.fail(Boolean.FALSE, hasRoleRt.getMsg(), hasRoleRt.getErrorCode());
        }

        return ServiceResult.success(hasRoleRt.getData());
    }

    @Override
    public ServiceResult<Boolean> checkReviewerPerm(String orgId, String userId) {
        // 校验参数
        if (!ObjectId.isValid(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "orgId");
        }
        if (!ObjectId.isValid(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "userId");
        }
        // 查询公司的审核配置
        ServiceResult<OrganizationDTO> orgRt = organizationService.selectByPrimaryKey(orgId);
        if (!orgRt.isSuccess()) {
            return ServiceResult.fail(Boolean.FALSE, orgRt.getMsg(), orgRt.getErrorCode());
        }
        OrganizationDTO org = orgRt.getData();
        if (org == null || (org.getDeliverCheckFlag() != null && OrgDeliverCheckFlagEnum.OPEN.getType().equals(org.getDeliverCheckFlag()))) {
            return ServiceResult.success(Boolean.FALSE);
        }

        // 查询用户是否有审核权限
        ServiceResult<Boolean> checkReviewerRt = this.checkReviewer(orgId, userId);
        if (!checkReviewerRt.isSuccess()) {
            return ServiceResult.fail(Boolean.FALSE, orgRt.getMsg(), orgRt.getErrorCode());
        }

        return ServiceResult.success(checkReviewerRt.getData());
    }

    @Override
    public ServiceResult<List<String>> listUserPermissions(String userId) {
        // 校验参数
        if (StringUtils.isBlank(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "userId不能为空");
        }
        // 查询并校验用户信息
        UserDTO userDTO = this.getUserByPrimaryKey(userId).getData();
        if (Objects.isNull(userDTO)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应的用户信息");
        }

        // 查询用户权限
        ServiceResult<Map<String, Set<String>>> userPermsRt = userBusinessService.listUserPermissions(userDTO.getUserId(), userDTO.getOrgId());
        if (!userPermsRt.isSuccess()) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应的用户公司信息");
        }
        Map<String, Set<String>> userPermMap = userPermsRt.getData();

        // 设置返回值并返回
        List<String> userPerms = new ArrayList<>();
        if (userPermMap != null && userPermMap.size() > 0) {
            for (Map.Entry<String, Set<String>> entry : userPermMap.entrySet()) {
                userPerms.addAll(entry.getValue().stream().map(e -> entry.getKey() + "." + e).collect(Collectors.toList()));
            }
        }
        return ServiceResult.success(userPerms);
    }

    @Override
    public ServiceResult<List<UserDTO>> selectByEmailOrOthers(String orgId, String keyword) {
        // 参数校验
        if (StringUtils.isBlank(orgId) || StringUtils.isBlank(keyword)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId和keyword都不能为空！");
        }
        // 搜索用户信息【模糊匹配email、name、userName、mobile】
        List<UserDO> userDos = userAccountDao.searchOrgIdBiShare(orgId, BooleanStatusEnum.NO.getStatus(), keyword);
        List<UserDTO> userDtos = userConvert.dos2Dtos(userDos);
        if (CollectionUtils.isNotEmpty(userDtos)) {
            for (UserDTO userDto : userDtos) {
                userDto.setSeniorFlag(BooleanStatusEnum.toBoolean(userBusinessService.checkSenior(userDto.getUserId(), orgId).getData()));
                userDto.setSuperFlag(BooleanStatusEnum.toBoolean(userBusinessService.checkSuper(userDto.getUserId(), orgId).getData()));
            }
        }

        return ServiceResult.success(userDtos);
    }

    @Override
    public ServiceResult<List<UserDTO>> listUserByOrCondition(UserDTO userDTO) {
        List<UserDO> userDOS = userAccountDao.listUserByOrCondition(userConvert.dto2Do(userDTO));
        return ServiceResult.success(userConvert.dos2Dtos(userDOS));
    }

    /**
     * 账号-修改姓名/账号/邮箱(绑定或解绑)/首页
     *
     * @param currentToken 当前token
     * @param userId       用户id
     * @param vo           可选参数
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/2 15:09
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<String> updateUserInfo(TokenDTO currentToken, String userId, UserInfoRequestVO vo) {
        String orgId = currentToken.getOrgId();
        UserDO userDO = userAccountDao.selectByPrimaryKey(userId);

        User user = new User();
        user.setUserId(userId);
        user.setOperatorId(userId);

        OrganizationDTO dto = new OrganizationDTO();
        dto.setOrgId(orgId);
        dto.setOperatorId(currentToken.getUserId());

        // 修改用户名
        if (StringUtils.isNotBlank(vo.getName())) {
            //参数验证
            String name = vo.getName();
            boolean matches = Pattern.matches(RegTypes.USER_NAME, name);
            if (!matches) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "姓名格式不符合规范");
            }
            user.setName(name);
        }

        // 修改账号
        if (StringUtils.isNotBlank(vo.getUserName())) {
            //参数验证
            String userName = vo.getUserName();
            boolean matches = Pattern.matches(RegTypes.USER_NAME, userName);
            if (!matches) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "账号名格式不符合规范");
            }

            // userName有改动时才更新该字段
            if (!userDO.getUserName().equals(userName)) {
                UserDO existUser = new UserDO();
                existUser.setOrgId(orgId);
                existUser.setUserName(userName);
                List<UserDO> userDOS = userAccountDao.selectByOrgIdSelective(existUser);
                if (CollectionUtils.isNotEmpty(userDOS)) {
                    return ServiceResult.fail(AuthErrorCodeEnum.USER_NAME_FOUND, "该账号名已存在");
                }
                user.setUserName(userName);
                dto.setAdminName(userName);
            }
        }

        // 修改邮箱
        if (Objects.nonNull(vo.getEmail())) {
            String email = vo.getEmail();
            //解绑邮箱
            if ("".equals(email)) {
                user.setEmail(email);
                dto.setAdminEmail(email);
            } else {
                //绑定邮箱
                Boolean emailValid = EmailUtil.validateEmail(email);
                if (emailValid.equals(Boolean.FALSE)) {
                    return ServiceResult.fail(ValidationErrorCodeEnum.EMAIL_ERROR);
                }
                ServiceResult<OrganizationDTO> result = organizationService.selectByPrimaryKey(orgId);
                if (Objects.isNull(result.getData())) {
                    return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "orgId不正确！");
                }
                //防刷检测
                ServiceResult<Boolean> checkFrequency = this.checkFrequency("bind_email_" + email, 60, 1);
                if (!checkFrequency.isSuccess()) {
                    return ServiceResult.fail(ResourceErrorCodeEnum.TOO_BUSY, "60s内不可以重复发送");
                }
                ServiceResult<String> serviceResult = this.sendBandEmail(userId, email, orgId, result.getData().getCode());
                if (!serviceResult.isSuccess()) {
                    return ServiceResult.fail(serviceResult.getErrorData(), serviceResult.getMsg());
                }
            }
        }

        // 修改首页
        if (Objects.nonNull(vo.getUserIndex())) {
            Integer userIndex = vo.getUserIndex();
            if (Objects.isNull(UserUserIndexEnum.getByType(userIndex))) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "userIndex不正确，超出合理范围");
            }
            user.setUserIndex(userIndex);
        }

        // 微信解绑
        if (Objects.nonNull(vo.getWxUnBind())) {
            Integer wxUnBind = vo.getWxUnBind();
            if (wxUnBind.equals(UserEnum.USER_YES.getFlag())) {
                ServiceResult<UserDTO> selectById = userService.selectById(userId);
                if (!selectById.isSuccess() || Objects.isNull(selectById.getData())) {
                    return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "userId不正确");
                }
                user.setWxUnionid("");
                user.setWxMiniOpenid("");
                user.setWxNickname("");

                // 发送MQ
                //weChatMessageSender.weChatUnBind(userId, currentToken.getOrgId(), selectById.getData().getWxOffiOpenid());
            }
        }

        // 更新密码
        if (Objects.nonNull(vo.getPassword())) {
            String password = vo.getPassword();

            ServiceResult<String> serviceResult = PwdUtil.checkPassword(password);
            if (!serviceResult.isSuccess()) {
                return ServiceResult.fail(serviceResult.getErrorCode(), serviceResult.getMsg());
            }
            if (StringUtils.isNotBlank(userDO.getPassword())) {
                return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "password 已经存在");
            }
            ServiceResult<String> resetPassword = resetPassword(userId, password);
            if (!resetPassword.isSuccess()) {
                return ServiceResult.fail(resetPassword.getMsg());
            }
        }

        // 更新是否同意用户协议
        if (Objects.nonNull(vo.getAccept())) {
            Boolean accept = vo.getAccept();
            user.setAcceptFlag(Boolean.TRUE.equals(accept) ? UserEnum.USER_YES.getFlag() : UserEnum.USER_NO.getFlag());
        }

        userAccountDao.updateByPrimaryKeySelective(user);
        //超级管理员同步修改公司的信息
        if (currentToken.getSuperRole().equals(BooleanStatusEnum.YES.getStatus())) {
            organizationService.updateByPrimaryKeySelective(dto);
        }
        return ServiceResult.success(userId);
    }

    /**
     * 修改账号
     *
     * @param currentToken 当前token
     * @param userId       用户id
     * @param userName
     * @return void
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/2 16:25
     */
    public ServiceResult<String> updateUserName(TokenDTO currentToken, String userId, String userName) {
        //参数验证
        if (userName.length() == 0 || userName.length() > 100) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "username长度超出合理范围");
        }

        //更新
        User user = new User();
        user.setUserId(userId);
        user.setUserName(userName);
        int i = userAccountDao.updateByPrimaryKeySelective(user);
        if (i != 1) {
            log.error("update user error userId:" + userId);
            return ServiceResult.fail("更新账号名失败");
        }

        //超级管理员同步修改公司的信息
        if (Objects.nonNull(currentToken) && currentToken.getSuperRole().equals(BooleanStatusEnum.YES.getStatus())) {
            OrganizationDTO dto = new OrganizationDTO();
            dto.setOrgId(currentToken.getOrgId());
            dto.setAdminName(userName);
            dto.setOperatorId(currentToken.getUserId());
            ServiceResult<Boolean> result = organizationService.updateByPrimaryKeySelective(dto);
            if (Boolean.FALSE.equals(result.getData())) {
                log.error("update organization error orgId:" + currentToken.getOrgId());
                return ServiceResult.fail("超级管理员同步修改公司的管理员账号名失败");
            }
        }

        return ServiceResult.success(userId);
    }

    /**
     * 防刷检测
     *
     * @param res
     * @param durian
     * @param limit
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Boolean>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/2 20:33
     */
    @Override
    public ServiceResult<Boolean> checkFrequency(String res, int durian, int limit) {
        res = "anti_fq_" + res;

        Long val;
        try {
            val = redisService.incr(res, 1);
        } catch (Exception e) {
            redisService.expire(res, durian, TimeUnit.SECONDS);
            return ServiceResult.fail("更新缓存失败！");
        }

        if (val == 1) {
            redisService.expire(res, durian, TimeUnit.SECONDS);
            return ServiceResult.success(true);
        } else if (val > limit) {
            return ServiceResult.fail(ResourceErrorCodeEnum.TOO_BUSY, String.format("no more than %d times durian %ss", limit, durian));
        }
        return ServiceResult.success(true);
    }

    /**
     * 发送绑定邮件
     *
     * @param userId
     * @param email
     * @param orgId
     * @param orgCode
     * @return void
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/3 11:00
     */
    @Override
    public ServiceResult<String> sendBandEmail(String userId, String email, String orgId, String orgCode) {
        //根据orgId、email查询user
        UserDO param = new UserDO();
        param.setOrgId(orgId);
        param.setEmail(email);
        List<UserDO> recordByEmail = userAccountDao.listByCondition(param);
        if (CollectionUtils.isNotEmpty(recordByEmail)) {
            return ServiceResult.fail(ValidationErrorCodeEnum.EMAIL_EXISTS_ERROR, "该email已被绑定");
        }

        String key = UserCacheKeyConstant.BIND_EMAIL_PREFIX + userId;
        Object activateToken = redisService.get(key);
        if (Objects.nonNull(activateToken)) {
            redisService.set(key, activateToken.toString(), 7200, TimeUnit.SECONDS);
        } else {
            redisService.set(key, UUID.randomUUID().toString(), 7200, TimeUnit.SECONDS);
            activateToken = redisService.get(key);
        }

        String encodeEmail;
        try {
            encodeEmail = URLEncoder.encode(email, "UTF-8");
        } catch (Exception e) {
            return ServiceResult.fail("email加密失败");
        }

        // 构建参数并生成短链接
        String orgUrl = userUtil.getCorpUrl(orgId, orgCode, settingProperties.getXmServerHost(), settingProperties.getServerProtocol());
        String activateUrl = orgUrl + "/activateEmail?uid=" + userId + "&token=" + activateToken.toString() + "&email=" + encodeEmail;
        String customDomainUrl = orgUrl;
        if (customDomainUrl.contains(settingProperties.getXmServerHost())) {
            customDomainUrl = null;
        }
        ServiceResult<String> shortUrlResult = apiHelperService.aioConvertShortUrl(activateUrl, customDomainUrl);
        if (!shortUrlResult.isSuccess()) {
            userCacheUtil.delete(key);
            return ServiceResult.fail(shortUrlResult.getData(), shortUrlResult.getMsg());
        }

        //组装参数
        UserDO nowUser = userAccountDao.selectByPrimaryKey(userId);
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", nowUser.getUserName());
        map.put("activate_url", shortUrlResult.getData());
        map.put("today", new SimpleDateFormat("yyyy年MM月dd日").format(new Date()));
        map.put("email_oss_path", getEmailOssPath());
        map.put("org_id", orgId);
        //发送邮件
        String subject = settingProperties.getBestcemEmailSign() + "邮箱验证";
        String fileName = EmailTemplateEnum.BAND_EMAIL_TEMPLATE.getFileName();

        boolean send = mailService.emailSendAndNotifyOm(new String[]{email}, new String[]{}, subject, fileName, map);
        if (!send) {
            userCacheUtil.delete(key);
            return ServiceResult.fail("发送绑定邮件失败 发件者 userId" + userId);
        }

        return ServiceResult.success(userId);
    }

    /**
     * 发送激活邮件/批量激活
     *
     * @param userIds
     * @param remoteHost
     * @param protocol
     * @return void
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/4 19:00
     */
    @Override
    public ServiceResult<String> activeEmailMany(List<String> userIds, String remoteHost, String protocol) {
        List<UserDO> users = userAccountDao.selectByIds(userIds);
        Map<String, UserDO> userIdUser = users.stream().collect(Collectors.toMap(UserDO::getUserId, Function.identity()));
        Set<String> orgIdSet = users.stream().map(UserDO::getOrgId).collect(Collectors.toSet());
        Map<String, String> userIdOrgId = new HashMap<>();
        for (UserDO user : users) {
            if (StringUtils.isBlank(user.getEmail())) {
                return ServiceResult.fail(ValidationErrorCodeEnum.USER_NAME_EMPTY, "user[id=" + user.getUserId() + "] email is empty");
            }
            if (!user.getStatus().equals(UserStatusEnum.INACTIVATED.getStatus())) {
                return ServiceResult.fail(ResourceErrorCodeEnum.STATUS_CHANGED, "user[id=" + user.getUserId() + "] status is " + user.getStatus());
            }
            userIdOrgId.put(user.getUserId(), user.getOrgId());
        }

        ServiceResult<List<OrganizationDTO>> organizationDTOResult = organizationService.selectByOrgIds(orgIdSet);
        List<OrganizationDTO> organizationDTOS = organizationDTOResult.getData();
        Map<String, OrganizationDTO> orgIdOrg = new HashMap<>();
        if (CollectionUtils.isNotEmpty(organizationDTOS)) {
            orgIdOrg = organizationDTOS.stream().collect(Collectors.toMap(OrganizationDTO::getOrgId, Function.identity()));
        }

        ArrayList<String> message = new ArrayList<>();
        for (Map.Entry<String, String> entry : userIdOrgId.entrySet()) {
            String userId = entry.getKey();
            String orgId = entry.getValue();
            UserDO user = userIdUser.get(userId);
            OrganizationDTO organizationDTO = orgIdOrg.get(orgId);
            ServiceResult<String> result = this.sendActiveEmail(userConvert.do2Dto(user), organizationDTO, remoteHost, protocol);
            if (!result.isSuccess()) {
                message.add(result.getMsg() + "userId:" + userId + "email" + userIdUser.get(userId).getEmail());
            }
        }
        if (CollectionUtils.isEmpty(message)) {
            return ServiceResult.success();
        } else {
            return ServiceResult.fail(message.get(0));
        }
    }

    @Override
    public ServiceResult<String> sendActiveEmail(UserDTO user, OrganizationDTO organization, String host, String protocol) {
        String key = UserCacheKeyConstant.ACTIVATE_TOKEN_PREFIX + user.getUserId();
        Object activateToken = redisService.get(key);
        if (Objects.nonNull(activateToken)) {
            redisService.set(key, activateToken.toString(), UserCacheKeyConstant.USER_TOKEN_TIMEOUT, TimeUnit.SECONDS);
        } else {
            activateToken = UUID.randomUUID().toString();
            redisService.set(key, activateToken, UserCacheKeyConstant.USER_TOKEN_TIMEOUT, TimeUnit.SECONDS);
        }

        String domain = userUtil.getOrgCustomSetting(organization.getOrgId());
        String activateUrl = protocol + "://" + (StringUtils.isNotBlank(domain) ? domain : host) + "/activityAccount?uid=" + user.getUserId() + "&token=" + activateToken;
        String loginUrl = protocol + "://" + (StringUtils.isNotBlank(domain) ? domain : host) + "/login";

        //组装参数
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", user.getName());
        map.put("user_name", user.getUserName());
        map.put("activate_url", activateUrl);
        map.put("companyCode", organization.getCode());
        map.put("companyName", organization.getName());
        map.put("email_oss_path", getEmailOssPath());
        map.put("loginUrl", loginUrl);

        //发送邮件
        String subject = "用户激活";
        String fileName = EmailTemplateEnum.ACTIVE_EMAIL_TEMPLATE.getFileName();
        boolean send = mailService.sendEmail(new String[]{user.getEmail()}, subject, fileName, map);

        // MQ消息
        String content = StringFormatUtil.templateFormat(fileName, map);
        SmsMessage smsMessage = new SmsMessage();
        smsMessage.setContent(content)
                .setName(subject)
                .setOrgId(user.getOrgId())
                .setReceiver(user.getEmail())
                .setSender("")
                .setType(NotifyTypeEnum.EMAIL.getType())
                .setStatus(send ? NotifyStatusEnum.IS_SEND.getType() : NotifyStatusEnum.SEND_FAILED.getType())
                .setSendTime(new SimpleDateFormat(DateUtil.NORM_DATETIME_PATTERN).format(DataBaseUtil.getDate()));

        // 发送MQ
        //userMessageSender.publishOmSmsSyc(smsMessage);

        if (!send) {
            redisService.del(key);
            return ServiceResult.fail("发送邮件至" + user.getEmail() + "异常");
        }
        return ServiceResult.success();
    }

    /**
     * 账号-绑定邮箱-验证邮件
     *
     * @param userId
     * @param email
     * @return com.bestcem.xm.util.ServiceResult<java.lang.String>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/4 20:51
     */
    @Override
    public ServiceResult<String> verificationEmail(String userId, String token, String email) {
        if (Boolean.FALSE.equals(EmailUtil.validateEmail(email))) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "email格式不正确");
        }
        if (!ObjectId.isValid(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "userId格式不正确");
        }

        String key = UserCacheKeyConstant.BIND_EMAIL_PREFIX + userId;
        Object cacheToken = redisService.get(key);
        if (Objects.isNull(cacheToken) || !token.equals(cacheToken.toString())) {
            return ServiceResult.fail(ReqErrorCodeEnum.TOKEN_LOST, "token不存在或者已过期");
        }

        UserDO user = userAccountDao.selectByPrimaryKey(userId);
        if (Objects.isNull(user)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "用户不存在");
        }

        UserDO userDO = new UserDO();
        userDO.setOrgId(user.getOrgId());
        userDO.setEmail(email);
        List<UserDO> recordByEmail = userAccountDao.listByCondition(userDO);
        if (CollectionUtils.isNotEmpty(recordByEmail)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "email已被其他用户绑定");
        }

        //验证是否为内部用户
        boolean checkUserIsInner = userUtil.checkUserIsInner(user.getPhone(), email, "");
        //绑定邮箱
        User update = new User();
        update.setUserId(userId);
        update.setEmail(email);
        update.setInnerFlag(checkUserIsInner ? UserInnerFlagEnum.INNER.getType() : UserInnerFlagEnum.OUTTER.getType());
        userAccountDao.updateByPrimaryKeySelective(update);

        // 根据orgId查询admin_role_id【ds_user_role】
        ServiceResult<String> adminRoleId = roleService.getAdminRole(user.getOrgId());
        if (!adminRoleId.isSuccess()) {
            return ServiceResult.fail(null, adminRoleId.getMsg(), adminRoleId.getErrorCode());
        }

        // 根据userId查询roleList【ds_user_role】
        UserUserRoleDTO userUserRoleDTO = new UserUserRoleDTO();
        userUserRoleDTO.setUserId(userId);
        ServiceResult<List<UserUserRoleDTO>> roleList = userUserRoleService.listByCondition(userUserRoleDTO);

        // 更新公司管理员邮箱
        List<String> roleIdList = roleList.getData().stream().map(UserUserRoleDTO::getRoleId).collect(Collectors.toList());
        if (roleIdList.contains(adminRoleId.getData())) {
            OrganizationDTO organizationDTO = new OrganizationDTO();
            organizationDTO.setOrgId(user.getOrgId());
            organizationDTO.setAdminEmail(email);
            organizationDTO.setInnerFlag(update.getInnerFlag());
            ServiceResult<Boolean> result = organizationService.updateByPrimaryKeySelective(organizationDTO);
            if (Boolean.FALSE.equals(result.getData())) {
                return ServiceResult.fail("超级管理员同步绑定公司的管理员邮箱失败");
            }
        }
        // mq消息通知
        //userMessageSender.publishUserUpdateContacts(userId, null, null, null, email);
        return ServiceResult.success(userId);
    }

    /**
     * 收到邮件后实际点击激活的页面
     * XM.apps_mysql.user.util.utils.activate_by_email
     *
     * @param userId
     * @param password
     * @return com.bestcem.xm.util.ServiceResult<java.lang.String>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/4 21:52
     */
    @Override
    public ServiceResult<String> activeEmail(String token, String userId, String password) {
        if (StringUtils.isBlank(password)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "password不能为空");
        }

        String key = UserCacheKeyConstant.ACTIVATE_TOKEN_PREFIX + userId;
        Object cachedToken = redisService.get(key);

        if (Objects.isNull(cachedToken) || !token.equals(cachedToken.toString())) {
            return ServiceResult.fail(ReqErrorCodeEnum.INVALID_TOKEN, "token失效或者token已过期");
        }

        ServiceResult<String> resetPassword = resetPassword(userId, password);
        if (!resetPassword.isSuccess()) {
            return ServiceResult.fail(resetPassword.getMsg());
        }

        User user = new User();
        user.setUserId(userId);
        user.setStatus(UserStatusEnum.ACTIVATED.getStatus());
        int row = userAccountDao.updateByPrimaryKeySelective(user);

        // 激活成功链接失效
        if (row == 1) {
            redisService.del(key);
            return ServiceResult.success(userId);
        }
        return ServiceResult.fail("激活失败");
    }


    /**
     * 账号-绑定手机号-发送验证码
     *
     * @param mobile
     * @param prefix 免费版注册：prefix: "USER:free_register"
     *               找回密码：prefix: "USER:find_pwd"
     *               手机号码绑定：prefix: "USER:mobile_bind"
     *               快速登录：prefix: "USER:fast_login"
     *               预约演示: prefix: "USER:Booking"
     *               biz预约: prefix:  "USER:biz"
     *               白皮书下载: "USER:whitepaper_subscribe"
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/6 16:54
     */
    @Override
    public ServiceResult<String> sendVerificationCode(String mobile, String prefix) {
        //根据prefix、mobile组装key,生成6位随机数字验证码vcode，并存入缓存,过期时间10分钟
        String key = prefix + ":" + mobile;
        String vcode = String.format("%06d", RandomUtils.nextInt(0, 1000000));
        redisService.set(key, vcode, 10L * 60, TimeUnit.SECONDS);

        //调用第三方接口发送验证码
        HashMap<String, Object> map = new HashMap<>();
        map.put("vcode", vcode);
        String content = StringFormatUtil.format(SmsConstant.SMS_VCODE_TEMPLATE, map);
        Boolean sendSms = userSmsService.sendSms(mobile, content);

        // 发送MQ
        if (StringUtils.isNotBlank(settingProperties.getAppName())) {
            String name = CommonConstant.NOTIFY_MAP.get(prefix);
            SmsMessage smsMessage = new SmsMessage();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("vcode", vcode);
            smsMessage.setContent(content)
                    .setName(StringUtils.isNotBlank(name) ? name : "")
                    .setOrgId("")
                    .setReceiver(mobile)
                    .setSender("")
                    .setType(NotifyTypeEnum.MOBILE.getType())
                    .setSmsChannel(NotifySmsChannelEnum.YIMEI.getType())
                    .setStatus(Boolean.TRUE.equals(sendSms) ? NotifyStatusEnum.IS_SEND.getType() :
                            NotifyStatusEnum.SEND_FAILED.getType())
                    .setSendTime(new SimpleDateFormat(DateUtil.NORM_DATETIME_PATTERN).format(DataBaseUtil.getDate()))
                    .setTemplateId("")
                    .setParams(jsonObject.toString());
            //userMessageSender.publishOmSmsSyc(smsMessage);
        }

        return ServiceResult.success();
    }

    /**
     * 账号-绑定手机号-绑定
     *
     * @param currentToken
     * @param userId
     * @param mobile
     * @param vcode
     * @param sceneType
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/6 23:53
     */
    @Override
    public ServiceResult<String> bindMobileNumber(TokenDTO currentToken, String userId, String mobile, String vcode, int sceneType) {
        String orgId = currentToken.getOrgId();
        ServiceResult<OrganizationDTO> organizationDTOServiceResult = organizationService.selectByPrimaryKey(orgId);
        OrganizationDTO dto = organizationDTOServiceResult.getData();

        String key = UserCacheKeyConstant.BIND_MOBILE_PREFIX + mobile;
        Object cacheCode = redisService.get(key);
        if (Objects.isNull(cacheCode) || !cacheCode.toString().equalsIgnoreCase(vcode)) {
            return ServiceResult.fail(ValidationErrorCodeEnum.VCODE_ERROR, "短信验证码不正确或已过期!");
        }

        UserDO user = userAccountDao.selectByPrimaryKey(userId);
        if (Objects.isNull(user)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "userId错误，用户不存在");
        }
//        2022-06-15 mfa相关需求 改为用户已绑定手机号的情况下可以修改
//        if (StringUtils.isNotBlank(user.getPhone())) {
//            return ServiceResult.fail(ValidationErrorCodeEnum.PHONE_EXISTS_ERROR, "当前用户已绑定手机号");
//        }

        UserDO userDO = new UserDO();
        userDO.setOrgId(orgId);
        userDO.setPhone(mobile);
        List<UserDO> userDOS = userAccountDao.listByCondition(userDO);
        if (CollectionUtils.isNotEmpty(userDOS)) {
            return ServiceResult.fail(ValidationErrorCodeEnum.PHONE_EXISTS_ERROR, "该手机号已被当前租户内其他用户绑定");
        }

        // 外部用户标记为内部用户，内部用户不会标记为外部用户
        User param = new User();
        param.setUserId(userId);
        param.setPhone(mobile);
        boolean checkUserIsInner = userUtil.checkUserIsInner(mobile, user.getEmail(), "");
        param.setInnerFlag(checkUserIsInner ? UserInnerFlagEnum.INNER.getType() : UserInnerFlagEnum.OUTTER.getType());
        userAccountDao.updateByPrimaryKeySelective(param);

        // 同步更新公司冗余的联系人号码
        if (BooleanStatusEnum.YES.getStatus().equals(currentToken.getSuperRole())) {
            // 同步修改公司的管理员信息
            OrganizationDTO organizationDTO = new OrganizationDTO();
            organizationDTO.setOrgId(orgId);
            organizationDTO.setAdminPhone(mobile);
            organizationDTO.setInnerFlag(param.getInnerFlag());
            organizationDTO.setOperatorId(currentToken.getUserId());
            organizationService.updateByPrimaryKeySelective(organizationDTO);

            // 首次绑定手机号码通知销售, 手动注册的公司
            ArrayList<Object> sourceList = new ArrayList<>();
            sourceList.add(OrgSourceEnum.REGISTER.getType());
            sourceList.add(OrgSourceEnum.WECHAT_MINI_REGISTTER.getType());

            ArrayList<Object> bindMobileSceneTypeList = new ArrayList<>();
            bindMobileSceneTypeList.add(EmailContentEnum.LOGIN_BIND_MOBILE.getType());
            bindMobileSceneTypeList.add(EmailContentEnum.DELIVER_BIND_MOBILE.getType());
            bindMobileSceneTypeList.add(EmailContentEnum.USER_INFO_BIND_MOBILE.getType());

            if (Objects.isNull(dto.getNotifySalesFlag()) && sourceList.contains(dto.getSource())
                    && bindMobileSceneTypeList.contains(sceneType)) {

                String content = EmailContentEnum.getByType(sceneType).getDesc();
                String industryName = "";
                if (Objects.nonNull(dto.getIndustryId())) {
                    // 根据industryId获取Industry
                    IndustryDTO industryDTO = industryGrpcService.getById(dto.getIndustryId());
                    industryName = industryDTO.getName();

                }
                NotifySalesDTO notifySalesDTO = new NotifySalesDTO(userConvert.do2Dto(user), orgId, organizationDTO.getName(),
                        content, organizationDTO.getNotifySalesFlag(), "", industryName, null);
                userUtil.notifySales(notifySalesDTO);
            }
            // mq消息通知
            //userMessageSender.publishUserUpdateContacts(userId, null, null, mobile, null);
        }
        // 发送更新用户信息的mq


        return ServiceResult.success(userId);
    }

    @Override
    public ServiceResult<Integer> countByPhoneAndStatus(String phone, Integer status) {
        return ServiceResult.success(userAccountDao.countByPhoneAndStatus(phone, status));
    }

    @Override
    public ServiceResult<UserDTO> selectByPhoneOrUnionId(String phone, String unionId, Integer status) {
        UserDO param = new UserDO();
        param.setStatus(status);
        if (StringUtils.isNotBlank(phone)) {
            param.setPhone(phone);
        } else if (StringUtils.isNotBlank(unionId)) {
            param.setWxUnionid(unionId);
        } else {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "phone和unionId不能同时为空");
        }

        List<UserDO> userDos = userAccountDao.selectList(param);
        if (CollectionUtils.isEmpty(userDos)) {
            return ServiceResult.success();
        }

        return ServiceResult.success(userConvert.do2Dto(userDos.get(0)));
    }

    @Override
    public ServiceResult<List<UserDTO>> selectByIds(List<String> userIdList) {
        List<UserDO> userDOs = userAccountDao.selectByIds(userIdList);
        return ServiceResult.success(userConvert.dos2Dtos(userDOs));
    }

    @Override
    public ServiceResult<String> insert(UserDTO userDTO) {
        String userId = userAccountDao.insertSelective(userConvert.dto2Do(userDTO));
        userDTO.setUserId(userId);
        return ServiceResult.success(userDTO.getUserId());
    }

    /**
     * 重置密码
     * XM.apps_mysql.user.util.utils.reset_password
     *
     * @param userId
     * @param password
     * @return void
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/4 22:14
     */
    @Override
    public ServiceResult<String> resetPassword(String userId, String password) {
        String autoPassword = "";
        if (StringUtils.isBlank(password)) {
            password = PwdUtil.genPassword();
            autoPassword = password;
        } else {
            //参数格式校验
            ServiceResult<String> checkPasswordRt = PwdUtil.checkPassword(password);
            if (!checkPasswordRt.isSuccess()) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "密码格式不符合要求");
            }
        }

        //密码加盐加密
        String salt = PwdUtil.genSalt();
        password = PwdUtil.getEncodePwd(password, salt);

        //重置密码并更新状态为已激活
        User user = new User();
        user.setUserId(userId);
        user.setPassword(password);
        user.setSalt(salt);
        user.setOperatorId(userId);
        userAccountDao.updateByPrimaryKeySelective(user);

        UserDO userDO = userAccountDao.selectByPrimaryKey(userId);

        // 邮件通知用户重置密码
        if (Objects.nonNull(userDO) && StringUtils.isNotBlank(autoPassword)) {
            String content = "您的密码重置为" + password;
            boolean sendEmail = mailService.sendEmail(new String[]{userDO.getEmail()}, "用户密码重置", content);
            if (!sendEmail) {
                return ServiceResult.fail("邮件发送失败");
            }
        }
        return ServiceResult.success(userId);
    }

    /**
     * 根据ids联表查询User列表
     *
     * @param roleId 可选条件
     * @param status 可选条件
     * @param ids    用户id列表
     * @param limit  查询结果限制条数
     * @return com.bestcem.xm.util.ServiceResult<com.bestcem.xm.user.service.dto.user.UserDTO>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/8 18:32
     */
    @Override
    public ServiceResult<List<UserDO>> listByIds(String roleId, Integer status, List<String> ids, Integer limit) {
        List<User> userList = userAccountDao.listByIds(roleId, status, ids, limit);
        return ServiceResult.success(userConvert.mysqls2Dos(userList));
    }

    /**
     * 解绑手机号
     *
     * @param userId
     * @return com.bestcem.xm.util.ServiceResult<java.lang.String>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/2 17:26
     */
    @Override
    public ServiceResult<String> unbindMobileNumber(TokenDTO currentToken, String userId) {
        User user = new User();
        user.setUserId(userId);
        user.setPhone("");
        user.setOperatorId(currentToken.getUserId());
        userAccountDao.updateByPrimaryKeySelective(user);

        //同步修改公司的管理员手机号码
        if (currentToken.getSuperRole() == 1) {
            OrganizationDTO organization = new OrganizationDTO();
            organization.setOrgId(currentToken.getOrgId());
            organization.setAdminPhone("");
            organization.setOperatorId(currentToken.getUserId());
            organizationService.updateByPrimaryKeySelective(organization);
        }

        return ServiceResult.success(userId);
    }


    @Override
    public ServiceResult<PageUserResponseDTO> getUserAccountList(ListUserAccountDTO accountDTO) {
        String userId = accountDTO.getUserId();
        String orgId = accountDTO.getOrgId();
        // 当前用户所在组及子组
        ServiceResult<List<String>> serviceResult = userGroupService.getChildrenGroupIdsByUserId(orgId, userId);
        List<String> childrenGroupIds = serviceResult.getData();

        ListUserAccountDO accountDO = new ListUserAccountDO();
        BeanUtils.copyProperties(accountDTO, accountDO);
        accountDO.setOrgId(orgId);
        accountDO.setBiShare(RoleBiShareEnum.NO_SHARE.getType());
        // 既不是系统管理员也不是高级管理员
        if (!(NumberUtils.INTEGER_ONE.equals(accountDTO.getAdmin()) || NumberUtils.INTEGER_ONE.equals(accountDTO.getSenior()))) {
            if (CollectionUtils.isEmpty(childrenGroupIds)) {
                // 用户未绑定任何的层级组织，不展示账号。
                return ServiceResult.success(new PageUserResponseDTO(new ArrayList<>(), NumberUtils.LONG_ZERO, accountDO.getPage(), NumberUtils.INTEGER_ZERO));
            }
            accountDO.setChildrenGroupIds(childrenGroupIds);
        }
        if (Objects.nonNull(accountDTO.getStatus())) {
            accountDO.setStatus(accountDTO.getStatus());
        }
        // 账号导出全部导出
        if (Objects.nonNull(accountDTO.getPageParam()) &&
                Objects.nonNull(accountDTO.getPageParam().getPage()) &&
                Objects.nonNull(accountDTO.getPageParam().getSize())) {
            accountDO.setPage(accountDTO.getPageParam().getPage());
            accountDO.setOffset(accountDTO.getPageParam().getOffset());
            accountDO.setSize(accountDTO.getPageParam().getSize());
        }

        // 不包含禁用账号的计数
        Integer userCount = userAccountDao.userAccountCount(orgId, UserStatusEnum.DISABLED.getStatus(), RoleBiShareEnum.NO_SHARE.getType());

        Long count = userAccountDao.getUserAccountListCount(accountDO);
        if (count == 0) {
            return ServiceResult.success(new PageUserResponseDTO(new ArrayList<>(), count, accountDO.getPage(), userCount));
        }
        List<UserAccountListDO> userAccountList = userAccountDao.getUserAccountList(accountDO);
        List<UserAccountListDTO> accountList = userConvert.accountDO2DTO(userAccountList);

        // 获取系统管理员
        ServiceResult<UserDTO> adminUserResult = userBusinessService.getAdminUserByOrgId(orgId);
        UserDTO adminUserDTO = adminUserResult.getData();
        for (UserAccountListDTO userAccount : accountList) {
            // 是否是系统管理员
            if (adminUserDTO != null) {
                userAccount.setSuperRole(userAccount.getUserId().equals(adminUserDTO.getUserId()));
            } else {
                userAccount.setSuperRole(false);
            }

            ServiceResult<List<String>> result = userUserRoleService.listRoleIdsByUserId(userAccount.getUserId());
            if (CollectionUtils.isNotEmpty(result.getData())) {
                userAccount.setRoleList(roleService.getRoleListByIdList(result.getData()).getData());
            } else {
                userAccount.setRoleList(new ArrayList<>());
            }

            ServiceResult<List<UserWithGroupDTO>> groupResult = userUserGroupService.getUserWithGroup(userAccount.getUserId());
            if (groupResult.isSuccess() && CollectionUtils.isNotEmpty(groupResult.getData())) {
                userAccount.setGroups(groupResult.getData());
            } else {
                userAccount.setGroups(new ArrayList<>());
            }
        }
        return ServiceResult.success(new PageUserResponseDTO(accountList, count, accountDO.getPage(), userCount));
    }

    /**
     * 下载模板
     *
     * @param
     * @return
     * @author 林志剑 <zhijian.lin@idiaoyan.cn>
     * @date 2022/03/01 15:57
     */
    @Override
    public ServiceResult<Boolean> downUserAccountTemplate(String path, HttpServletResponse response) {
        String templateName = "账号导入模版";
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        try {
            String fileName = URLEncoder.encode(templateName, "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            ClassPathResource resource = new ClassPathResource(path);
            EasyExcelFactory.write(response.getOutputStream()).withTemplate(resource.getInputStream()).build().finish();
        } catch (Exception e) {
            log.error("用户模版下载失败", e);
            return ServiceResult.fail("用户模版下载失败");
        }
        return ServiceResult.success();
    }

    /**
     * 导出账号数据
     *
     * @param accountDTO
     * @return
     * @author 林志剑 <zhijian.lin@idiaoyan.cn>
     * @date 2022/03/01 15:57
     */
    @Override
    public ServiceResult<List<ExportUserAccountDTO>> exportUserData(ListUserAccountDTO accountDTO) {
        // 获取当前所有账号
        ServiceResult<PageUserResponseDTO> serviceResult = getUserAccountList(accountDTO);
        List<UserAccountListDTO> data = serviceResult.getData().getRows();
        for (UserAccountListDTO userAccount : data) {
            // 拼接角色名称
            if (CollectionUtils.isNotEmpty(userAccount.getRoleList())) {
                String roleNames = userAccount.getRoleList().stream().map(UserRoleDTO::getName).collect(Collectors.joining(","));
                userAccount.setRoleNames(roleNames);
            }
            ServiceResult<List<UserWithGroupDTO>> result = userUserGroupService.getUserWithGroup(userAccount.getUserId());
            if (result.isSuccess() && CollectionUtils.isNotEmpty(result.getData())) {
                String groupCode = result.getData().stream().map(UserWithGroupDTO::getCode).collect(Collectors.joining(","));
                String groupNames = result.getData().stream().map(UserWithGroupDTO::getName).collect(Collectors.joining(","));
                userAccount.setGroupCode(groupCode);
                userAccount.setGroupNames(groupNames);
            }
        }
        List<ExportUserAccountDTO> exportData = userConvert.userAccount2Export(data);

        return ServiceResult.success(exportData);
    }

    /**
     * 获取用户详情
     *
     * @param userId
     * @return
     * @author 林志剑 <zhijian.lin@idiaoyan.cn>
     * @date 2022/03/01 15:57
     */
    @Override
    public ServiceResult<UserDTO> getUserByPrimaryKey(String userId) {
        UserDO user = userAccountDao.selectByPrimaryKey(userId);
        return ServiceResult.success(userConvert.do2Dto(user));
    }

    /**
     * 解析数据
     *
     * @param userDTOList:
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ServiceResult<Void> parseUserData(String orgId, List<ImportUserAccountDTO> userDTOList, String currentId) {

        // 如果账号和邮箱数据库中存在就是更新
        UserDO userDO = new UserDO();
        userDO.setOrgId(SecurityContextHolder.getToken().getOrgId());
        List<UserDO> userDOList = userAccountDao.listByCondition(userDO);
        // 数据库中存在的账号和邮箱
        List<String> usernameList = userDOList.stream().map(UserDO::getUserName).collect(Collectors.toList());
        List<String> emailList = userDOList.stream().map(UserDO::getEmail).collect(Collectors.toList());
        List<String> phoneList = userDOList.stream().map(UserDO::getPhone).filter(Objects::nonNull).collect(Collectors.toList());

        List<ImportUserAccountDTO> insertList = new ArrayList<>();
        List<ImportUserAccountDTO> updateList = new ArrayList<>();
        Set<String> usernameSet = new HashSet<>();
        Set<String> emailSet = new HashSet<>();
        Set<String> phoneSet = new HashSet<>();

        // 系统管理员和高级管理员的用户名集合
        Set<String> manageSet = new HashSet<>();
        // 获取系统管理员
        ServiceResult<UserDTO> adminUserResult = userBusinessService.getAdminUserByOrgId(orgId);
        UserDTO adminUser = adminUserResult.getData();
        manageSet.add(adminUser.getUserName());

        // 获取高级管理员
        ServiceResult<List<UserDTO>> seniorUserResult = userBusinessService.getSeniorAdminByOrgId(orgId);
        List<UserDTO> seniorUserList = seniorUserResult.getData();
        if (CollectionUtils.isNotEmpty(seniorUserList)) {
            manageSet.addAll(seniorUserList.stream().map(UserDTO::getUserName).collect(Collectors.toSet()));
        }

        // 判断用户是新增还是更新
        for (ImportUserAccountDTO importUser : userDTOList) {

            // 不允许修改系统管理员和高级管理员
            if (manageSet.contains(importUser.getUserName())) {
                // 系统管理员，高级管理员不处理
                continue;
            }

            if (StringUtils.isBlank(importUser.getUserName()) || StringUtils.isBlank(importUser.getEmail()) ||
                    StringUtils.isBlank(importUser.getName())) {
                return ServiceResult.fail("账号名称或姓名或邮箱缺失");
            }

            if (StringUtils.isBlank(importUser.getRole()) || StringUtils.isBlank(importUser.getGroupCode())) {
                return ServiceResult.fail("所属组织编码或角色缺失");
            }

            if (importUser.getUserName().length() > BusinessConstant.USERNAME_MAX_LENGTH) {
                return ServiceResult.fail(String.format("账号名 %s 超过长度限制", importUser.getUserName()));
            }
            if (importUser.getName().length() > BusinessConstant.USERNAME_MAX_LENGTH) {
                return ServiceResult.fail(String.format("姓名 %s 超过长度限制", importUser.getName()));
            }

            if (StringUtils.isNotBlank(importUser.getPhone()) && !importUser.getPhone().matches(RegTypes.MOBILE)) {
                return ServiceResult.fail(String.format("手机号 %s 格式错误", importUser.getPhone()));
            }

            if (!Boolean.TRUE.equals(EmailUtil.validateEmail(importUser.getEmail()))) {
                return ServiceResult.fail(String.format("邮箱 %s 格式错误", importUser.getEmail()));
            }

            if (usernameSet.contains(importUser.getUserName())) {
                return ServiceResult.fail("账号名称:" + importUser.getUserName() + "重复");
            }
            if (emailSet.contains(importUser.getEmail())) {
                return ServiceResult.fail("邮箱:" + importUser.getEmail() + "重复");
            }
            if (phoneSet.contains(importUser.getPhone())) {
                return ServiceResult.fail("手机号:" + importUser.getPhone() + "重复");
            }
            if (StringUtils.isNotBlank(importUser.getContent()) && importUser.getContent().length() > 60) {
                return ServiceResult.fail("备注:" + importUser.getContent() + "超过长度限制");
            }
            if (usernameList.contains(importUser.getUserName())) {
                // // 校验已存在用户的手机号
                if (StringUtils.isNotBlank(importUser.getPhone())) {
                    List<UserDTO> userListByPhone = userService.getUserListByUsernameOrEmailOrPhone(orgId, null, importUser.getPhone(), null);
                    if (CollectionUtils.isNotEmpty(userListByPhone) && !userListByPhone.get(0).getUserName().equals(importUser.getUserName())) {
                        return ServiceResult.fail("手机号:" + importUser.getPhone() + "重复");
                    }
                }
                // 校验已存在用户的邮箱
                List<UserDTO> userListByEmail = userService.getUserListByUsernameOrEmailOrPhone(orgId, null, null, importUser.getEmail());
                if (CollectionUtils.isNotEmpty(userListByEmail) && !userListByEmail.get(0).getUserName().equals(importUser.getUserName())) {
                    return ServiceResult.fail("邮箱:" + importUser.getEmail() + "重复");
                }
                updateList.add(importUser);
            } else {
                if (emailList.contains(importUser.getEmail())) {
                    return ServiceResult.fail("邮箱:" + importUser.getEmail() + "已存在");
                }
                if (phoneList.contains(importUser.getPhone())) {
                    return ServiceResult.fail("手机号:" + importUser.getPhone() + "已存在");
                }
                insertList.add(importUser);
            }
            usernameSet.add(importUser.getUserName());
            emailSet.add(importUser.getEmail());
            if (StringUtils.isNotBlank(importUser.getPhone())) {
                phoneSet.add(importUser.getPhone());
            }
        }
        // 检查租户用户限额
        ServiceResult<Boolean> result = checkUserQuota(orgId, insertList.size());
        // 用户数已达上限
        if (!Boolean.TRUE.equals(result.getData())) {
            return ServiceResult.fail(result.getErrorData(), result.getMsg());
        }
        // 更新组织
        Map<String, List<String>> updateUserIdAndGroupIdsMap = new HashMap<>(updateList.size());
        // 更新用户
        for (ImportUserAccountDTO updateUser : updateList) {
            List<UserDO> userList = userAccountDao.getUserListByUsernameOrEmailOrPhone(orgId, updateUser.getUserName(), null, null);
            if (CollectionUtils.isEmpty(userList)) {
                return ServiceResult.fail(String.format("账号名称: %s 不存在", updateUser.getUserName()));
            }
            UserDO user = userList.get(0);
            // 检查角色是否存在 不存在则添加
            List<String> newRoleIdList = new ArrayList<>();
            if (StringUtils.isNotBlank(updateUser.getRole())) {
                List<String> roleNameList = Arrays.asList(updateUser.getRole().replace("，", ",").split(","));
                if (roleNameList.contains(RolePermsEnum.ADMIN.getName()) || roleNameList.contains(RolePermsEnum.SENIOR_ADMIN.getName())) {
                    return ServiceResult.fail("不允许添加高级管理员或系统管理员角色");
                }
                ServiceResult<List<String>> roleIdListService = roleService.checkRoleExistAndSave(orgId, roleNameList);
                newRoleIdList = roleIdListService.getData();
            }
            // 当前用户的角色id
            UserUserRoleDTO userUserRoleDTO = new UserUserRoleDTO();
            userUserRoleDTO.setUserId(user.getUserId());
            ServiceResult<List<UserUserRoleDTO>> roleIdsService = userUserRoleService.listByCondition(userUserRoleDTO);
            List<String> oldRoleIdList = roleIdsService.getData().stream().map(UserUserRoleDTO::getRoleId).collect(Collectors.toList());
            // 检查user中是否有角色的变更 并更新权限
            userUserRoleService.checkUserRoleChangeAndUpdate(orgId, user.getUserId(), newRoleIdList, oldRoleIdList, currentId);

            List<String> newGroupIds = new ArrayList<>();
            if (StringUtils.isNotBlank(updateUser.getGroupCode())) {
                // 中英文逗号转换
                String[] groupCode = updateUser.getGroupCode().replace("，", ",").split(",");
                List<Integer> statusList = Collections.singletonList(UserGroupStatusEnum.ACTIVATED.getStatus());
                ServiceResult<List<UserGroupDTO>> listServiceResult = userGroupService.listGroupsByCodes(orgId, Arrays.asList(groupCode), statusList);
                List<UserGroupDTO> groupList = listServiceResult.getData();

                if (CollectionUtils.isEmpty(groupList) || groupList.size() != groupCode.length) {
                    throw new ServiceException(ReqErrorCodeEnum.PARAM_LOST, String.format("账号 %s 组织不存在", updateUser.getUserName()));
                } else {
                    newGroupIds.addAll(groupList.stream().map(UserGroupDTO::getGroupId).collect(Collectors.toList()));
                }
                if (CollectionUtils.isNotEmpty(newGroupIds)) {
                    userUserGroupService.updateUserGroups(orgId, user.getUserId(), newGroupIds);
                }
            }
            UserDO userUpdate = new UserDO();
            userUpdate.setUserId(user.getUserId());
            userUpdate.setName(updateUser.getName());
            userUpdate.setEmail(updateUser.getEmail());
            userUpdate.setPhone(updateUser.getPhone());
            userUpdate.setContent(updateUser.getContent());
            userUpdate.setOperatorId(currentId);
            userAccountDao.updateAccountById(userConvert.do2Mysql(userUpdate));
            // 高级管理员添加全部项目入口
            userUserRoleService.checkSeniorRole(orgId, user.getUserId(), newRoleIdList, oldRoleIdList);
            // 记录更新用户
            updateUserIdAndGroupIdsMap.put(user.getUserId(), newGroupIds);
        }
        List<String> insertUserIdList = new ArrayList<>();
        // 新增用户
        Map<String, List<String>> createUserIdAndGroupIdsMap = new HashMap<>(insertList.size());
        for (ImportUserAccountDTO insertUser : insertList) {
            List<String> newRoleIdList = new ArrayList<>();
            if (StringUtils.isNotBlank(insertUser.getRole())) {
                List<String> roleNameList = Arrays.asList(insertUser.getRole().replace("，", ",").split(","));
                if (roleNameList.contains(RolePermsEnum.ADMIN.getName()) || roleNameList.contains(RolePermsEnum.SENIOR_ADMIN.getName())) {
                    return ServiceResult.fail("不允许添加高级管理员或系统管理员角色");
                }
                // 检查角色是否存在 不存在则添加
                ServiceResult<List<String>> roleIdListService = roleService.checkRoleExistAndSave(orgId, roleNameList);
                newRoleIdList = roleIdListService.getData();
            }

            List<String> groupIds = new ArrayList<>();
            if (StringUtils.isNotBlank(insertUser.getGroupCode())) {
                String[] groupCode = insertUser.getGroupCode().replace("，", ",").split(",");
                List<Integer> statusList = Collections.singletonList(UserGroupStatusEnum.ACTIVATED.getStatus());
                ServiceResult<List<UserGroupDTO>> listServiceResult = userGroupService.listGroupsByCodes(orgId, Arrays.asList(groupCode), statusList);
                List<UserGroupDTO> groupList = listServiceResult.getData();
                if (CollectionUtils.isEmpty(groupList) || groupList.size() != groupCode.length) {
                    throw new ServiceException(ReqErrorCodeEnum.PARAM_LOST, String.format("账号 %s 组织不存在", insertUser.getUserName()));
                } else {
                    groupIds.addAll(groupList.stream().map(UserGroupDTO::getGroupId).collect(Collectors.toList()));
                }

            }
            UserDTO userDTO = new UserDTO();
            BeanUtils.copyProperties(insertUser, userDTO);
            userDTO.setStatus(UserStatusEnum.INACTIVATED.getStatus());
            String userId = userService.saveUser(orgId, userDTO, groupIds, newRoleIdList);
            insertUserIdList.add(userId);
            // 记录创建用户
            createUserIdAndGroupIdsMap.put(userDTO.getUserId(), groupIds);
        }
        // 邮箱激活
        userAsyncUtil.activeEmailManyAsync(insertUserIdList, settingProperties.getXmServerHost(), settingProperties.getServerProtocol());
        updateUserConsumption(orgId, insertList.size());

        // 事务提交后发送消息
        TransactionHelper.runAfterCommit(() -> {
            for (Map.Entry<String, List<String>> e : updateUserIdAndGroupIdsMap.entrySet()) {
                userMessageSendService.publishUserUpdate(e.getKey(), e.getValue());
            }
            for (Map.Entry<String, List<String>> e : createUserIdAndGroupIdsMap.entrySet()) {
                userMessageSendService.publishUserCreate(e.getKey(), e.getValue());
            }
        });

        return ServiceResult.success();
    }

    @Override
    public ServiceResult<Boolean> updateUserPassword(String userId, String password, String salt) {
        User user = new User();
        user.setUserId(userId);
        user.setPassword(password);
        user.setSalt(salt);
        user.setUpdateTime(new Date());
        int result = userAccountDao.updateByPrimaryKeySelective(user);
        return ServiceResult.success(result == 1);
    }

    /**
     * 更新User信息
     * XM.apps_mysql.user.util.utils.update_user
     *
     * @param params
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Boolean>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/8 20:12
     */
    @Override
    public ServiceResult<UserDTO> updateUser(UserDTO params) {
        UserDO oldUser = userAccountDao.selectByPrimaryKey(params.getUserId());
        if (Objects.isNull(oldUser)) {
            log.error("update_user user_id=[" + params.getUserId() + "] failed. old_user not found.");
            return ServiceResult.fail("old_user user_id=[" + params.getUserId() + "] not found.");
        }

//        需要提供给定制使用 这个地方不做限制
//        if (oldUser.getStatus().equals(UserStatusEnum.INACTIVATED.getStatus()) && !params.getStatus().equals(oldUser.getStatus())) {
//            return ServiceResult.fail("he status cannot be changed when the user is not activated");
//        }

        UserDO userDO = userConvert.dto2Do(params);
        User user = userConvert.do2Mysql(userDO);
        if (!oldUser.getStatus().equals(user.getStatus()) && UserStatusEnum.INACTIVATED.getStatus().equals(user.getStatus())) {
            int i = userAccountDao.updateByPrimaryKeySelective(user);
            if (i != 1) {
                return ServiceResult.fail("用户更新失败");
            }
            updateUserConsumption(oldUser.getOrgId(), -1);
        } else if (!oldUser.getStatus().equals(user.getStatus()) && UserStatusEnum.ACTIVATED.getStatus().equals(user.getStatus())) {
            ServiceResult<Boolean> userQuota = checkUserQuota(oldUser.getOrgId(), 1);
            if (!Boolean.TRUE.equals(userQuota.getData())) {
                return ServiceResult.fail(ResourceErrorCodeEnum.QUOTA_REACHED);
            }
            int i = userAccountDao.updateByPrimaryKeySelective(user);
            if (i != 1) {
                return ServiceResult.fail("用户更新失败");
            }
            updateUserConsumption(oldUser.getOrgId(), 1);
        } else {
            userAccountDao.updateByPrimaryKeySelective(user);
        }

        UserDO newUser = userAccountDao.selectByPrimaryKey(user.getUserId());
        return ServiceResult.success(userConvert.do2Dto(newUser));
    }

    @Override
    public ServiceResult<Boolean> updateAcceptAndInnerUser() {
        userAccountDao.updateUserAcceptFlag(UserAccpectFlagEnum.ACCPECT.getType(), UserAccpectFlagEnum.NOT_ACCPECT.getType());
        //if settings.IS_XM:
        if (settingProperties.getIsXm()) {
            List<UserDO> userDOList = userAccountDao.getUserInnerIsNull();
            for (UserDO userDO : userDOList) {
                boolean checkUserIsInner = userUtil.checkUserIsInner(userDO.getPhone(), userDO.getEmail(), "");
                userDO.setInnerFlag(checkUserIsInner ? UserInnerFlagEnum.INNER.getType() : UserInnerFlagEnum.OUTTER.getType());
                userAccountDao.updateByPrimaryKey(userDO);
            }
        } else {
            userAccountDao.updateUserInner(UserInnerFlagEnum.OUTTER.getType());
        }
        return ServiceResult.success(Boolean.TRUE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<UserDTO> getOrCreateBiShareTempUser(String orgId) {
        if (StringUtils.isBlank(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId not be null");
        }
        UserDTO result = null;

        // 查询是否已经存在该用户信息，不存在则新增
        String tempUserName = orgId + "_temp_user_for_bi_share";
        UserDO userParam = new UserDO();
        userParam.setOrgId(orgId);
        userParam.setUserName(tempUserName);
        List<UserDO> userInfos = userAccountDao.selectList(userParam);
        if (CollectionUtils.isNotEmpty(userInfos)) {
            // 用户存在
            result = userConvert.do2Dto(userInfos.get(0));
        } else {
            // 用户不存在，创建用户信息
            result = new UserDTO();
            result.setStatus(UserStatusEnum.ACTIVATED.getStatus());
            result.setUserName(tempUserName);
            result.setName(tempUserName);
            result.setContent(tempUserName);
            result.setEmail(tempUserName + "@idiaoyan.com");
            result.setOrgId(orgId);
            result.setBiShareFlag(BooleanStatusEnum.YES.getStatus());
            userAccountDao.insertSelective(userConvert.dto2Do(result));
        }

        // 查询权限是否存在，不存在则新增
        String tempRoleName = "bishare_temp";
        String roleId = "";
        UserRoleDTO userRoleParam = new UserRoleDTO();
        userRoleParam.setOrgId(orgId);
        userRoleParam.setName(tempRoleName);
        ServiceResult<List<UserRoleDTO>> roleInfos = roleService.selectByCondition(userRoleParam);
        if (roleInfos.isSuccess() && CollectionUtils.isNotEmpty(roleInfos.getData())) {
            // 角色存在
            roleId = roleInfos.getData().get(0).getRoleId();
        } else {
            // 角色不存在，新增
            UserRoleDTO userRoleDTO = new UserRoleDTO();
            userRoleDTO.setOrgId(orgId);
            userRoleDTO.setName(tempRoleName);
            userRoleDTO.setContent(tempRoleName);
            userRoleDTO.setBiShare(1);
            ServiceResult<String> insertRoleResult = roleService.saveUserRole(userRoleDTO);
            if (!insertRoleResult.isSuccess()) {
                // 回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ServiceResult.fail("新增临时角色失败");
            }
            roleId = insertRoleResult.getData();
        }

        // 保存角色权限内容信息
        String permission = "{\"PROJECT_DATAREPORT\": [\"DATAREPORT.ENTRY\",\"REPORT.VIEW\"]}";
        ServiceResult<RolePermissionDTO> rolePermissionInfos = rolePermissionService.selectByOrgIdAndRoleId(orgId, roleId);
        if (!rolePermissionInfos.isSuccess() || Objects.isNull(rolePermissionInfos.getData())) {
            // 新增权限
            RolePermissionDTO rolePermissionDTO = new RolePermissionDTO();
            rolePermissionDTO.setRoleId(roleId);
            rolePermissionDTO.setPermission(permission);
            rolePermissionService.insertSelective(rolePermissionDTO);
        } else {
            // 更新权限
            RolePermissionDTO data = rolePermissionInfos.getData();
            data.setPermission(permission);
            rolePermissionService.updateByPrimaryKeySelective(data);
        }

        // 更新用户的角色信息
        List<String> roleIds = new ArrayList<>();
        roleIds.add(roleId);
        userUserRoleService.checkUserRoleChangeAndUpdate(orgId, result.getUserId(), roleIds, new ArrayList<>(), "");
        return ServiceResult.success(result);
    }

    @Override
    public ServiceResult<List<UserDTO>> getUserByCondition(UserDTO userDTO) {
        UserDO userDO = userConvert.dto2Do(userDTO);
        List<UserDO> userDOList = userAccountDao.listByCondition(userDO);
        return ServiceResult.success(userConvert.dos2Dtos(userDOList));
    }

    @Override
    public ServiceResult<UserDTO> getOneUserByFilter(UserDTO userDTO) {
        UserDO userDO = userConvert.dto2Do(userDTO);
        UserDO user = userAccountDao.getOneUserByFilter(userDO);
        return ServiceResult.success(userConvert.do2Dto(user));
    }

    @Override
    public ServiceResult<Integer> updateByOrgIdSelective(UserDTO userDTO) {
        if (StringUtils.isBlank(userDTO.getOrgId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId不能为空");
        }
        Integer count = userAccountDao.updateByOrgIdSelective(userConvert.dto2Do(userDTO));
        return ServiceResult.success(count);
    }

    @Override
    public ServiceResult<Integer> countByOrgId(String orgId) {
        return ServiceResult.success(userAccountDao.countByOrgId(orgId));
    }

    @Override
    public List<UserDTO> getUserListByCreateTimeSort(UserDTO userDTO) {
        UserDO userDO = userConvert.dto2Do(userDTO);
        List<UserDO> userDOList = userAccountDao.getUserListByCreateTimeSort(userDO);
        return userConvert.dos2Dtos(userDOList);
    }

    @Override
    public List<UserDTO> getUserListByUsernameOrEmailOrPhone(String orgId, String username, String phone, String email) {
        List<UserDO> userDOList = userAccountDao.getUserListByUsernameOrEmailOrPhone(orgId, username, phone, email);
        return userConvert.dos2Dtos(userDOList);
    }

    @Override
    public Integer updateUserByQyWxOpenUserid(String qyWxOpenUserid) {
        return userAccountDao.updateUserByQyWxOpenUserid(qyWxOpenUserid);
    }


    @Override
    public ServiceResult<List<UserDO>> selectByOrgIdSelective(UserDTO user) {
        List<UserDO> userDOS = userAccountDao.selectByOrgIdSelective(userConvert.dto2Do(user));
        return ServiceResult.success(userDOS);
    }


    @Override
    public ServiceResult<List<String>> getUserPermissionList(String orgId, String userId) {
        List<String> permissionList = new ArrayList<>();
        ServiceResult<List<String>> roleResult = userUserRoleService.listRoleIdsByUserId(userId);
        List<String> roleList = roleResult.getData();
        // 超级管理员添加所有权限
        ServiceResult<String> adminRoleService = roleService.getAdminRole(orgId);
        String adminRoleId = adminRoleService.getData();
        if (roleList.contains(adminRoleId)) {
            permissionList.add(CommonConstant.ALL_PERMISSION);
        }
        ServiceResult<List<RolePermissionDTO>> permissionResult = rolePermissionService.listByRoleIds(roleList, orgId);
        if (permissionResult.isSuccess()) {
            List<RolePermissionDTO> permissionDTOList = permissionResult.getData();
            List<String> permissions = permissionDTOList.stream().map(RolePermissionDTO::getPermission).collect(Collectors.toList());
            permissionList.addAll(permissions);
        }
        return ServiceResult.success(permissionList);
    }

    @Override
    public ServiceResult<UserSelfDTO> getUserSelf(String userId, String orgId) {
        UserDO userDO = userAccountDao.selectByPrimaryKey(userId);
        if (Objects.isNull(userDO)) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "用户不存在");
        }
        ServiceResult<List<UserGroupDTO>> userGroupResult = userGroupService.getGroupsByUserIdLeftJoinGroup(userId);
        UserSelfDTO selfDTO = UserConverter.userSelfDO2DTO(userDO);
        if (userGroupResult.isSuccess() && CollectionUtils.isNotEmpty(userGroupResult.getData())) {
            selfDTO.setGroups(userGroupResult.getData());
        }
        if (StringUtils.isNotBlank(selfDTO.getShowGuideRecords())) {
            selfDTO.setGuide(JSON.parseArray(selfDTO.getShowGuideRecords(), String.class));
        } else {
            selfDTO.setGuide(new ArrayList<>());
        }
        selfDTO.setIsSuper(userBusinessService.checkSuper(userId, orgId).getData() == 1);
        selfDTO.setIsSenior(userBusinessService.checkSenior(userId, orgId).getData() == 1);
        selfDTO.setHasPassword(StringUtils.isNotBlank(userDO.getPassword()));
        selfDTO.setWxNickname(StringUtils.isNotBlank(selfDTO.getWxOffiOpenid()) ? "已绑定" : "");
        // 设置roleIndex
        RoleIndexName roleIndexName = getRoleIndex(orgId, userId);
        selfDTO.setRoleIndex(roleIndexName.getRoleIndex());
        selfDTO.setRoleList(roleIndexName.getRoleList());
        return ServiceResult.success(selfDTO);
    }

    private RoleIndexName getRoleIndex(String orgId, String userId) {
        RoleIndexName roleIndexName = new RoleIndexName();
        // 当前用户所拥有的角色id
        ServiceResult<List<String>> userRoleIdListResult = userUserRoleService.listRoleIdsByUserId(userId);
        if (CollectionUtils.isEmpty(userRoleIdListResult.getData())) {
            return new RoleIndexName();
        }
        ServiceResult<List<UserRoleDTO>> roleList = roleService.getRoleListByIdList(userRoleIdListResult.getData());
        List<UserRoleDTO> userRoleList = roleList.getData();
        List<String> roleNameList = userRoleList.stream().map(UserRoleDTO::getName).filter(Objects::nonNull).collect(Collectors.toList());
        roleIndexName.setRoleList(roleNameList);
        // 当前用户所拥有的所有权限
        ServiceResult<List<RolePermissionDTO>> permissionResult = rolePermissionService.listByRoleIds(userRoleIdListResult.getData(), orgId);
        // 权限为空的情况
        if (CollectionUtils.isNotEmpty(permissionResult.getData())) {
            // 权限不为空的情况
            List<RolePermissionDTO> permissionDTOList = permissionResult.getData();
            HashMap<String, Integer> rolePermissionMap = new HashMap<>();
            List<Integer> permissionLenList = new ArrayList<>();
            for (RolePermissionDTO rolePermissionDTO : permissionDTOList) {
                JSONObject permission = JSON.parseObject(rolePermissionDTO.getPermission());
                int permissionLen = 0;
                if (Objects.nonNull(permission)) {
                    // rolePermissionMap存储的是角色id对应的permission个数
                    for (Map.Entry<String, Object> entry : permission.entrySet()) {
                        permissionLen = permissionLen + ((List<String>) entry.getValue()).size();
                        rolePermissionMap.put(rolePermissionDTO.getRoleId(), permissionLen);
                    }
                }
                permissionLenList.add(permissionLen);
            }
            // 取最大的permission数量
            Integer max = Collections.max(permissionLenList);
            // 最大的permission对应的roleId
            List<String> roleIdList = new ArrayList<>();
            for (Map.Entry<String, Integer> entrySet : rolePermissionMap.entrySet()) {
                Integer length = rolePermissionMap.get(entrySet.getKey());
                if (max.equals(length)) {
                    roleIdList.add(entrySet.getKey());
                }
            }
            if (roleIdList.size() != 1) {
                List<UserRoleDTO> userRoleIndexList = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(roleIdList)) {
                    ServiceResult<List<UserRoleDTO>> roleIndexList = roleService.getRoleListByIdList(roleIdList);
                    userRoleIndexList = roleIndexList.getData();
                }
                List<Integer> roleIndexList = userRoleIndexList.stream().map(UserRoleDTO::getRoleIndex).filter(Objects::nonNull).collect(Collectors.toList());
                // 当角色首页都为none，返回none
                if (CollectionUtils.isEmpty(roleIndexList)) {
                    return roleIndexName;
                }
                // 权限数量相同时，按优先级
                Integer roleIndex = Collections.min(roleIndexList);
                roleIndexName.setRoleIndex(roleIndex);
                return roleIndexName;
            }
            UserRoleDTO check = new UserRoleDTO();
            check.setRoleId(roleIdList.get(0));
            ServiceResult<List<UserRoleDTO>> result = roleService.selectByCondition(check);
            Integer roleIndex = result.getData().get(0).getRoleIndex();
            roleIndexName.setRoleIndex(roleIndex);
        }
        return roleIndexName;
    }

    @Override
    public ServiceResult<PageResponseDTO<TicketUserDTO>> pageTicketUsers(PageRequestDTO pageDto, String orgId, String search) {
        if (Objects.isNull(pageDto) || Objects.isNull(pageDto.getPage()) || Objects.isNull(pageDto.getSize())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "分页参数不能为空");
        }
        // 获取当前公司的系统管理员角色
        ServiceResult<String> adminRole = roleService.getAdminRole(orgId);
        if (!adminRole.isSuccess() || StringUtils.isBlank(adminRole.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "Role not found");
        }
        // 查询系统管理员用户id信息
        ServiceResult<List<String>> listServiceResult = userUserRoleService.listUserIdsByRoleId(adminRole.getData());
        List<String> allUserIds = new ArrayList<>();
        if (listServiceResult.isSuccess() && CollectionUtils.isNotEmpty(listServiceResult.getData())) {
            allUserIds = listServiceResult.getData();
        }

        // 获取公司的根组织信息
        ServiceResult<UserGroupDTO> rootGroupByOrgId = userGroupService.getRootGroupByOrgId(orgId);
        if (rootGroupByOrgId.isSuccess() && Objects.nonNull(rootGroupByOrgId.getData())) {
            String groupId = rootGroupByOrgId.getData().getGroupId();
            // 获取根组织对应的用户id信息
            ServiceResult<List<String>> groupUserIdsResult = userUserGroupService.listByGroupId(groupId);
            if (groupUserIdsResult.isSuccess() && CollectionUtils.isNotEmpty(groupUserIdsResult.getData())) {
                allUserIds.addAll(groupUserIdsResult.getData());
            }
        }

        PageResponseDTO<TicketUserDTO> result = new PageResponseDTO<>();
        result.setRows(new ArrayList<>());
        result.setPage(pageDto.getPage());
        // search模糊匹配userName、name、email
        Long count = userAccountDao.countByNameOrUserNameOrEmail(orgId, search, UserStatusEnum.ACTIVATED.getStatus(), allUserIds);
        result.setTotal(count);
        if (count <= 0) {
            return ServiceResult.success(result);
        }

        // 分页查询信息
        // search模糊匹配userName、name、email
        List<UserDO> userDos = userAccountDao.pageByNameOrUserNameOrEmail(orgId, search, UserStatusEnum.ACTIVATED.getStatus(),
                allUserIds, (pageDto.getPage() - 1) * pageDto.getSize(), pageDto.getSize());
        if (CollectionUtils.isNotEmpty(userDos)) {
            List<TicketUserDTO> collect = userDos.stream().map(u -> {
                TicketUserDTO ticket = new TicketUserDTO();
                ticket.setId(u.getUserId());
                ticket.setName(u.getName());
                ticket.setEmail(u.getEmail());
                return ticket;
            }).collect(Collectors.toList());
            result.setRows(collect);
        }

        return ServiceResult.success(result);
    }

    @Override
    public ServiceResult<PageResponseDTO<TicketUserDTO>> pageTicketUsersWithGroup(PageParam pageParam, String orgId, String search) {
        PageResponseDTO<TicketUserDTO> result = new PageResponseDTO<>();
        result.setRows(new ArrayList<>());
        result.setPage(pageParam.getPage());
        // search模糊匹配name、email
        Long count = userAccountDao.countByNameOrEmailAndWithGroup(orgId, search, UserStatusEnum.ACTIVATED.getStatus());
        result.setTotal(count);
        if (count <= 0) {
            return ServiceResult.success(result);
        }

        // 不分页情况
        Integer offset = null;
        if (Objects.nonNull(pageParam.getPage()) && Objects.nonNull(pageParam.getSize())) {
            offset = pageParam.getOffset();
        }

        // 分页查询信息
        // search模糊匹配name、email
        List<UserDO> userDos = userAccountDao.pageByNameOrEmailAndWithGroup(orgId, search, UserStatusEnum.ACTIVATED.getStatus(), offset, pageParam.getSize());
        if (CollectionUtils.isNotEmpty(userDos)) {
            List<TicketUserDTO> collect = userDos.stream().map(u -> {
                TicketUserDTO ticket = new TicketUserDTO();
                ticket.setId(u.getUserId());
                ticket.setName(u.getName());
                ticket.setEmail(u.getEmail());
                return ticket;
            }).collect(Collectors.toList());
            result.setRows(collect);
        }

        return ServiceResult.success(result);
    }

    @Override
    public ServiceResult<List<TicketUserDTO>> listTicketUsers(String orgId, String search) {
        // 获取当前公司的系统管理员角色
        ServiceResult<String> adminRole = roleService.getAdminRole(orgId);
        if (!adminRole.isSuccess() || StringUtils.isBlank(adminRole.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "Role not found");
        }
        // 查询系统管理员用户id信息
        ServiceResult<List<String>> listServiceResult = userUserRoleService.listUserIdsByRoleId(adminRole.getData());
        String superUserId = "";
        List<String> allUserIds = new ArrayList<>();
        if (listServiceResult.isSuccess() && CollectionUtils.isNotEmpty(listServiceResult.getData())) {
            superUserId = listServiceResult.getData().get(0);
            allUserIds = listServiceResult.getData();
        }
        final String tempSuperUserId = superUserId;

        // 获取公司的根组织信息
        ServiceResult<UserGroupDTO> rootGroupByOrgId = userGroupService.getRootGroupByOrgId(orgId);
        if (rootGroupByOrgId.isSuccess() && Objects.nonNull(rootGroupByOrgId.getData())) {
            String groupId = rootGroupByOrgId.getData().getGroupId();
            // 获取根组织对应的用户id信息
            ServiceResult<List<String>> groupUserIdsResult = userUserGroupService.listByGroupId(groupId);
            if (groupUserIdsResult.isSuccess() && CollectionUtils.isNotEmpty(groupUserIdsResult.getData())) {
                allUserIds.addAll(groupUserIdsResult.getData());
            }
        }
        if (CollectionUtils.isNotEmpty(allUserIds)) {
            // 根据相关参数，查询用户信息列表
            List<UserDO> userDos = userAccountDao.pageByNameOrUserNameOrEmail(orgId, search, UserStatusEnum.ACTIVATED.getStatus(), allUserIds, null, null);
            if (CollectionUtils.isNotEmpty(userDos)) {
                List<TicketUserDTO> result = new ArrayList<>();
                List<TicketUserDTO> collect = userDos.stream().map(u -> {
                    TicketUserDTO ticket = new TicketUserDTO();
                    ticket.setId(u.getUserId());
                    ticket.setName(u.getName());
                    ticket.setEmail(u.getEmail());
                    return ticket;
                }).collect(Collectors.toList());
                TicketUserDTO ticketUserDTO = collect.stream().filter(c -> tempSuperUserId.equals(c.getId())).findFirst().orElse(null);
                if (Objects.nonNull(ticketUserDTO)) {
                    result.add(ticketUserDTO);
                }
                result.addAll(collect.stream().filter(c -> !tempSuperUserId.equals(c.getId())).collect(Collectors.toList()));
                return ServiceResult.success(result);
            }
        }
        return ServiceResult.success(new ArrayList<>());
    }

    @Override
    public ServiceResult<List<UserRoleDTO>> getRoleAccount(String orgId) {

        List<UserRoleDTO> userRoleList = new ArrayList<>();
        // 通过条件查询可分配的角色
        UserRoleDTO roleDTO = new UserRoleDTO();
        roleDTO.setOrgId(orgId);
        roleDTO.setType(RoleTypeEnum.COMMON.getType());
        roleDTO.setBiShare(RoleBiShareEnum.NO_SHARE.getType());
        ServiceResult<List<UserRoleDTO>> serviceResult = roleService.selectByCondition(roleDTO);
        if (serviceResult.isSuccess() && CollectionUtils.isNotEmpty(serviceResult.getData())) {
            userRoleList = serviceResult.getData();
        }
        // 添加高级管理员id 高级管理员也是可以被分配给用户的角色
        String seniorAdminRoleId = roleService.getSeniorAdminRole(orgId).getData();
        UserRoleDTO check = new UserRoleDTO();
        check.setRoleId(seniorAdminRoleId);
        ServiceResult<List<UserRoleDTO>> result = roleService.selectByCondition(check);
        if (result.isSuccess() && CollectionUtils.isNotEmpty(result.getData())) {
            userRoleList.add(result.getData().get(0));
        }
        return ServiceResult.success(userRoleList);
    }

    @Override
    public ServiceResult<List<UserDTO>> getUserByEmailOrPhone(Integer status, String email, String phone) {
        List<UserDO> userDOList = userAccountDao.getUserByEmailOrPhone(status, email, phone);
        return ServiceResult.success(userConvert.dos2Dtos(userDOList));
    }

    @Override
    public ServiceResult<List<UserDTO>> listUsers(UserConditionDTO userConditionDTO, List<Integer> statuses, String search, List<String> fields) {
        // 去重并映射到表字段
        String tableFields = null;
        if (CollectionUtils.isNotEmpty(fields)) {
            Set<String> tempSet = new HashSet<>(fields);
            tableFields = tempSet.stream().map(CommonConstant.USER_FIELD_MAP::get).filter(StringUtils::isNotBlank).collect(Collectors.joining(StrUtil.COMMA));
        }

        // 整合组织状态
        if (CollectionUtils.isEmpty(statuses)) {
            statuses = new ArrayList<>();
        }
        Integer status = userConditionDTO.getStatus();
        if (Objects.nonNull(status) && !statuses.contains(status)) {
            statuses.add(status);
        }

        UserDO userDO = UserConditionConvert.dto2Do(userConditionDTO);
        List<UserDO> list = userAccountDao.listUsers(userDO, statuses, search, tableFields);
        if (Objects.isNull(list)) {
            ServiceResult.fail("【用户中心】根据搜索条件查询用户列表失败");
        }
        return ServiceResult.success(userConvert.dos2Dtos(list));
    }

    @Override
    public ServiceResult<Void> unbindWechatWork(String orgId, String openUserid) {
        if (StringUtils.isBlank(orgId) && StringUtils.isBlank(openUserid)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId和openUserid不能都为空");
        }
        userAccountDao.unbindWechatWork(orgId, openUserid);
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<Void> unbindFeishu(String orgId, String openId) {
        if (StringUtils.isBlank(orgId) && StringUtils.isBlank(openId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId和openId不能都为空");
        }
        userAccountDao.unbindFeishu(orgId, openId);
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<List<String>> listByRoleIdJoinUserRole(String dstOrgId, String dstAdminRoleId) {
        List<String> userIds = userAccountDao.listByRoleIdJoinUserRole(dstOrgId, dstAdminRoleId);
        return ServiceResult.success(userIds);
    }

    @Override
    public List<UserDO> listUsersByGroupLevelAndRoleId(List<UserConditionLevel> conditionsList, String orgId) {
        // 需要6张表关联查询，太慢，还是分别查出来，在java里组装后判断吧
        // 1.查询该租户的所有group_level和所有的group
        List<UserGroupLevelDO> groupLevels = userGroupLevelDao.getGroupLevelsByOrgId(orgId);
        List<UserGroupDO> userGroupDOS = userGroupDao.listByOrgIdOrPage(orgId, null, null, false);

        // 2.拼装成一个map，key是groupLevelId，value是该level的所有group
        Map<String, List<String>> map = new HashMap<>();
        for (UserGroupLevelDO groupLevel : groupLevels) {
            List<String> groupIdList = new LinkedList<>();
            for (UserGroupDO userGroupDO : userGroupDOS) {
                String groupLevelId = userGroupDO.getGroupLevelId();
                if (groupLevelId != null && groupLevelId.equals(groupLevel.getGroupLevelId())) {
                    groupIdList.add(userGroupDO.getGroupId().toLowerCase());
                }
            }
            map.put(groupLevel.getGroupLevelId().toLowerCase(), groupIdList);
        }

        // 3.根据角色查询用户的role_group关联信息
        List<String> roleIds = conditionsList.stream().map(UserConditionLevel::getRoleId).collect(Collectors.toList());
        List<UserRoleGroupDO> roleGroupList = userRoleDao.getRoleGroupByRoleIds(orgId, roleIds);

        // 4.循环roleGroupList判断符合UserConditionLevel条件(同时匹配groupLevelId和roleId)的记录，过滤出来，就是想要得到的用户id集合
        List<String> userIds = new LinkedList<>();
        for (UserRoleGroupDO userRoleGroup : roleGroupList) {
            for (UserConditionLevel userCondition : conditionsList) {
                List<String> list = map.get(userCondition.getGroupLevelId().toLowerCase());
                if (userRoleGroup.getRoleId().equalsIgnoreCase(userCondition.getRoleId()) && list.contains(userRoleGroup.getGroupId().toLowerCase())) {
                    userIds.add(userRoleGroup.getUserId());
                }
            }
        }

        // 5.根据用户ids查询用户详情列表，返回
        return userAccountDao.selectByIds(userIds);
    }

    @Override
    public ServiceResult<List<String>> getUserIdsByRoleAndOrgAndStatus(String roleId, String orgId, List<Integer> status) {
        if (StringUtils.isEmpty(roleId) || StringUtils.isEmpty(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "roleId和orgId都不能为空");
        }
        List<String> userIds = userAccountDao.getUserIdsByRoleAndOrgAndStatus(roleId, orgId, status);
        return ServiceResult.success(userIds);
    }

    @Override
    public ServiceResult<List<UserDTO>> selectByOrgAndEmailAndUserIds(String orgId, String email, List<String> userIds) {
        if (StringUtils.isEmpty(orgId) || StringUtils.isEmpty(email)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "roleId和email都不能为空");
        }
        List<UserDO> userDos = userAccountDao.selectByOrgAndEmailAndUserIds(orgId, email, userIds);
        if (CollectionUtils.isEmpty(userDos)) {
            return ServiceResult.success(new ArrayList<>());
        }
        return ServiceResult.success(userConvert.dos2Dtos(userDos));
    }

    @Override
    public ServiceResult<List<UserDTO>> selectByOrgAndPhonePhoneAndUserIds(String orgId, String phone, List<String> userIds) {
        if (StringUtils.isEmpty(orgId) || StringUtils.isEmpty(phone)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "roleId和phone都不能为空");
        }
        List<UserDO> userDos = userAccountDao.selectByOrgAndPhonePhoneAndUserIds(orgId, phone, userIds);
        if (CollectionUtils.isEmpty(userDos)) {
            return ServiceResult.success(new ArrayList<>());
        }
        return ServiceResult.success(userConvert.dos2Dtos(userDos));
    }

    @Override
    public ServiceResult<Void> updateByUserIds(List<String> userIds, UserDTO user) {
        if (CollectionUtils.isEmpty(userIds) || Objects.isNull(user)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "userIds和user信息都不能为空！");
        }
        userAccountDao.updateByUserIds(userIds, userConvert.dto2Do(user));
        return ServiceResult.success();
    }

    @Override
    public void updateInnerFlagByOrgIds(List<String> orgIds, Integer innerFlag) {
        userAccountDao.updateInnerFlagByOrgIds(orgIds, innerFlag);
    }

    @Override
    public ServiceResult<Boolean> checkVcode(String prefix, String phone, String vCode) {
        String codeValue = userCacheUtil.get(prefix + ":" + phone);
        if (StringUtils.isBlank(codeValue)) {
            return ServiceResult.fail(ValidationErrorCodeEnum.VCODE_EXPIRED);
        }
        return ServiceResult.success(codeValue.equals(vCode));
    }

    @Override
    public ServiceResult<Map<String, String>> listIdsByUserName(Set<String> userNames, String orgId) {
        // 校验参数
        if (CollectionUtils.isEmpty(userNames) || !ObjectId.isValid(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT.getMsg());
        }

        // 分批查询 避免sql超出长度
        List<List<String>> userNameBatch = ListUtils.partition(new ArrayList<>(userNames), CommonConstant.PARTITION_SIZE);
        Map<String, String> usernameAndIdMap = new HashMap<>();
        for (List<String> userNameList : userNameBatch) {
            HashSet<String> userNameSet = new HashSet<>(userNameList);
            List<UserDO> userDOList = userAccountDao.listIdsByUserName(userNameSet, orgId);
            // 未查询 返回错误结果
            if (CollectionUtils.isEmpty(userDOList)) {
                return this.listIdsByUserNameFail(userNameList.get(0), usernameAndIdMap);
            }
            // 未查询到全部 返回错误结果
            if (userDOList.size() < userNameList.size()) {
                Set<String> existUserNameSet = userDOList.stream().map(UserDO::getUserName).collect(Collectors.toSet());
                userNameSet.removeAll(existUserNameSet);
                return this.listIdsByUserNameFail(new ArrayList<>(userNameSet).get(0), usernameAndIdMap);
            }
            // 查询成功 数量没有问题 添加为对应的返回值
            Map<String, String> usernameAndIdMapBatch = userDOList.stream().collect(Collectors.toMap(UserDO::getUserName, UserDO::getUserId));
            usernameAndIdMap.putAll(usernameAndIdMapBatch);
        }

        return ServiceResult.success(usernameAndIdMap);
    }

    /**
     * 设置查询失败返回值: 根据用户名查询用户信息(仅返回userId和userName)
     *
     * @param userName
     * @return ServiceResult<List < UserDTO>>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/8/2 15:43
     */
    private ServiceResult<Map<String, String>> listIdsByUserNameFail(String userName, Map<String, String> usernameAndIdMap) {
        usernameAndIdMap.put(userName, StringUtils.EMPTY);
        return ServiceResult.fail(usernameAndIdMap, ResourceErrorCodeEnum.NO_DATA.getMsg(), String.valueOf(ResourceErrorCodeEnum.NO_DATA.getCode()));
    }

    /**
     * 校验找回密码的参数
     *
     * @param findType 找回类型
     * @param email    邮件
     * @param mobile   手机号
     * @param vcode    验证码
     * @return com.bestcem.xm.util.ServiceResult<java.lang.String>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/05/26 21:32
     */
    private ServiceResult<String> checkFindPasswordParam(FindPasswordTypeEnum findType, String email, String mobile, String vcode) {
        if (Objects.isNull(findType)) {
            return ServiceResult.fail("ttype参数错误");
        }

        switch (findType) {
            case EMAIL:
                // 邮箱校验
                if (StringUtils.isBlank(email)) {
                    return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "email不能为空！");
                }
                Boolean validateEmail = EmailUtil.validateEmail(email);
                if (!BooleanStatusEnum.YES.getBoolValue().equals(validateEmail)) {
                    return ServiceResult.fail(ValidationErrorCodeEnum.EMAIL_ERROR, "email格式有误！");
                }
                return ServiceResult.success(email);
            case PHONE:
                // 手机号校验
                if (StringUtils.isBlank(mobile)) {
                    return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "mobile不能为空！");
                }
                if (!Pattern.compile(RegTypes.MOBILE).matcher(mobile).matches()) {
                    return ServiceResult.fail(ValidationErrorCodeEnum.PHONE_ERROR, "mobile格式有误！");
                }
                if (StringUtils.isBlank(vcode)) {
                    return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "请输入短信验证码！");
                }
                /*
                 * 20200718 手机找回增加验证码，所以螺丝帽在验证码那一步做了
                 * # saas平台测试、开发、生产环境使用螺丝帽验证，其他使用验证码
                 *     luotest_response = params.get('luotest_response')
                 * await self.check_frequency('reset_pwd_v3_' + contact + luotest_response, 60, 1)
                 * if not luotest_response:
                 * raise RequestError(RequestError.ParamLost, luotest_response)
                 * await check_luosimao_captcha(luotest_response)
                 *
                 * 2020/11/09
                 * 非SaaS 环境同样不校验图片验证码
                 * 使用手机号码找回的，加上校验短信验证码
                 */
                // 校验验证码的有效性
                Object cacheVcode = redisService.get(UserCacheKeyConstant.FIND_PWD_KEY + mobile);
                if (Objects.isNull(cacheVcode) || !cacheVcode.toString().equalsIgnoreCase(vcode)) {
                    return ServiceResult.fail(ValidationErrorCodeEnum.VCODE_ERROR, "短信验证码错误！");
                }
                return ServiceResult.success(mobile);
            default:
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "ttype参数错误");
        }
    }


    @Override
    public ServiceResult<PageUserResponseDTO> getAllUserAccountList(ListUserAccountDTO accountDTO) {
        String userId = accountDTO.getUserId();
        String orgId = accountDTO.getOrgId();

        ListUserAccountDO accountDO = new ListUserAccountDO();
        BeanUtils.copyProperties(accountDTO, accountDO);
        accountDO.setOrgId(orgId);
        accountDO.setBiShare(RoleBiShareEnum.NO_SHARE.getType());
        // 既不是系统管理员也不是高级管理员
        if (!(NumberUtils.INTEGER_ONE.equals(accountDTO.getAdmin()) || NumberUtils.INTEGER_ONE.equals(accountDTO.getSenior()))) {
            // 当前用户所在组及子组
            ServiceResult<List<String>> serviceResult = userGroupService.getChildrenGroupIdsByUserId(orgId, userId);
            List<String> childrenGroupIds = serviceResult.getData();
            if (CollectionUtils.isEmpty(childrenGroupIds)) {
                // 用户未绑定任何的层级组织，不展示账号。
                return ServiceResult.success(new PageUserResponseDTO(new ArrayList<>(), NumberUtils.LONG_ZERO, accountDO.getPage(), NumberUtils.INTEGER_ZERO));
            }
            accountDO.setChildrenGroupIds(childrenGroupIds);
        }
        if (Objects.nonNull(accountDTO.getStatus())) {
            accountDO.setStatus(accountDTO.getStatus());
        }
        // 账号导出全部导出
        if (Objects.nonNull(accountDTO.getPageParam()) &&
                Objects.nonNull(accountDTO.getPageParam().getPage()) &&
                Objects.nonNull(accountDTO.getPageParam().getSize())) {
            accountDO.setPage(accountDTO.getPageParam().getPage());
            accountDO.setOffset(accountDTO.getPageParam().getOffset());
            accountDO.setSize(accountDTO.getPageParam().getSize());
        }

        // 不包含禁用账号的计数
        Integer userCount = userAccountDao.userAccountCount(orgId, UserStatusEnum.DISABLED.getStatus(), RoleBiShareEnum.NO_SHARE.getType());

        Long count = userAccountDao.getUserAccountListCount(accountDO);
        if (count == 0) {
            return ServiceResult.success(new PageUserResponseDTO(new ArrayList<>(), count, accountDO.getPage(), userCount));
        }
        List<UserAccountListDO> userAccountList = userAccountDao.getUserAccountList(accountDO);
        List<UserAccountListDTO> accountList = userConvert.accountDO2DTO(userAccountList);

        // 获取系统管理员
        ServiceResult<UserDTO> adminUserResult = userBusinessService.getAdminUserByOrgId(orgId);
        UserDTO adminUserDTO = adminUserResult.getData();
        for (UserAccountListDTO userAccount : accountList) {
            // 是否是系统管理员
            if (adminUserDTO != null) {
                userAccount.setSuperRole(userAccount.getUserId().equals(adminUserDTO.getUserId()));
            } else {
                userAccount.setSuperRole(false);
            }
        }
        return ServiceResult.success(new PageUserResponseDTO(accountList, count, accountDO.getPage(), userCount));
    }

}
